2015年7月24日金曜日

日本の海岸線データの加工

かなり国土地理院のデータを間引いて、なんとか100MBのデータを数MBまでにしましたが、ノートPCなんかで使うにはまだまだサイズが大きいです。思い切って1/100に間引いてみましたが、日本の海岸線が途切れてしまいます。
やはり少し頭を使って、元になる国土地理院の海岸線データの特徴を調べてみます。

1.海岸線データの固まり方
先にも言いましたが、元データは県別のxmlデータになっていて、行政界、島毎にタグが分かれています。それを緯度経度だけ抽出してくると以下ののようになります。
35.04924833 136.83906528
35.05145167 136.83815250
35.05175111 136.83802834
   

35.05899417 136.87838278
35.05921944 136.87846166
35.05952000 136.87857805
35.05949694 136.87866195
35.05947139 136.87874555
35.05914306 136.87861805
35.05894917 136.87855139
35.05899417 136.87838278
   

35.05730000 136.87774750
35.05771861 136.87788778

途中、2行の空白行がありますが、そこが行政界の区切り、あるいは島のデータの始まりを表します。上記サンプルを見ると、2つ目のデータの固まりのデータの始まりと終わり(6行目と13行目です)が同じ緯度経度になっています。つまりこれは島だということです。
前回のプログラムでは、以下に注意しました。

  • 行政界、島の区切りを示す空白行は残す。
  • 空白行を出力したところで間引きカウンタを0クリアして、空白行に続く先頭データは積極的に出力する。


しかし、特に島のデータに顕著にでましたが、あまり間引く数が大きいときはデータの固まりの最後(空白行の直前のデータ)も残してやらないと島が閉曲線になりません。

2,改良版プログラム
ということで、島の最後のデータも残してやるように改修しました。
#!/usr/bin/python
# coding: utf-8

import sys

if __name__ == "__main__":
 argv = sys.argv  # コマンドライン引数を格納したリストの取得
 argc = len(argv)  # 引数の個数

# print argv
# print argc

 fi = open(argv[1], 'r')
 fo = open(argv[2], 'w')

 # n行に1回出力するようにする
 ct = 0

 preLine = ""

 for line in fi:
  if line.strip() == "": # 島等のデータとの境界である空白行は残すようにする
   if (preLine.strip() != ""): # 空白行の直前のデータは残す(島の閉曲線を守るため)
    fo.write(preLine)
   fo.write(line)
   ct = 0 # 島のデータは少ないので1行でも残す
   preLine = line
   continue

  if ct == 0:
   fo.write(line)

  ct = ct + 1
  preLine = line

  if ct == 100:  # 100行に1回出力する
   ct = 0

 fi.close()
 fo.close()

さてこれで1/100に間引いてみましたが、どうもデータのサイズが思うように小さくなりません。

3.改良版の処理結果を見る
再度、処理結果を調べてみました。
35.08614861 136.89070723
35.08342250 136.86787278
35.05776194 136.84691778
35.06403806 136.84048584
   

35.05175111 136.83802834
35.05175111 136.83802834
   

35.05899417 136.87838278
35.05899417 136.87838278

確かに島のデータは残されるようになっていますが、思いの外国土地理院のデータには小島がしっかりはいっているようで、同じ緯度経度が2回連続する固まりが大量にありました。こいつらは改良版のプログラムではどんなに間引率を大きくしても残されるようにしてあるため、思ったようにデータのサイズが小さくならなかったようです。
でも実際日本地図を使うようなときはこんな小島、表示もされないのでデータの無駄です。

4.小島のデータを削除する
手作業で削除するかとも思ったんですが、すぐに諦めました。さすがにデータのサイズが小さくならない原因だけあって大量に存在しています。あきらめて、2行同じ緯度経度のデータが続く箇所はフィルタするようなプログラムを作りました。(行政界の他のところで偶然そういう場所がないか、という恐れはありますがまあ少しくらい抜けてもそれに気づくほど拡大して使うことはないでしょう。もし使う必要があるなら、それはもう手作業でなんとかしてやるしかありません)
#!/usr/bin/python
# coding: utf-8

import sys

if __name__ == "__main__":
 argv = sys.argv  # コマンドライン引数を格納したリストの取得
 argc = len(argv)  # 引数の個数

# print argv
# print argc

 fi = open(argv[1], 'r')
 fo = open(argv[2], 'w')

 # n行に1回出力するようにする
 ct = 0

 preLine = ""

 for line in fi:
  if line.strip() == "": # 島等のデータとの境界である空白行は残すようにする
   if (preLine.strip() != ""): # 空白行の直前のデータは残す(島の閉曲線を守るため)
    fo.write(preLine)
   fo.write(line)
   ct = 0 # 島のデータは少ないので1行でも残す
   preLine = line
   continue

  if preLine != line:
   fo.write(preLine)
  else:
   preLine = ""
   line = ""
   continue

  preLine = line


 fi.close()
 fo.close()

かなり手抜きプログラムですが、これでサイズを1/100にし、かつ2行しかないような小島のデータを削除して、データサイズが1.4MBまで縮小できました。結果を以下に示します。

先日の海岸線とほとんど見た目は変わりません。よく見れば、小さな小島は消えているんですがね。




0 件のコメント:

コメントを投稿