2015年7月24日金曜日

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

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

1.海岸線データの固まり方
先にも言いましたが、元データは県別のxmlデータになっていて、行政界、島毎にタグが分かれています。それを緯度経度だけ抽出してくると以下ののようになります。
  1. 35.04924833 136.83906528
  2. 35.05145167 136.83815250
  3. 35.05175111 136.83802834
  4.  
  5. 35.05899417 136.87838278
  6. 35.05921944 136.87846166
  7. 35.05952000 136.87857805
  8. 35.05949694 136.87866195
  9. 35.05947139 136.87874555
  10. 35.05914306 136.87861805
  11. 35.05894917 136.87855139
  12. 35.05899417 136.87838278
  13.  
  14. 35.05730000 136.87774750
  15. 35.05771861 136.87788778

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

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


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

2,改良版プログラム
ということで、島の最後のデータも残してやるように改修しました。
  1. #!/usr/bin/python
  2. # coding: utf-8
  3.  
  4. import sys
  5.  
  6. if __name__ == "__main__":
  7. argv = sys.argv # コマンドライン引数を格納したリストの取得
  8. argc = len(argv) # 引数の個数
  9.  
  10. # print argv
  11. # print argc
  12.  
  13. fi = open(argv[1], 'r')
  14. fo = open(argv[2], 'w')
  15.  
  16. # n行に1回出力するようにする
  17. ct = 0
  18.  
  19. preLine = ""
  20.  
  21. for line in fi:
  22. if line.strip() == "": # 島等のデータとの境界である空白行は残すようにする
  23. if (preLine.strip() != ""): # 空白行の直前のデータは残す(島の閉曲線を守るため)
  24. fo.write(preLine)
  25. fo.write(line)
  26. ct = 0 # 島のデータは少ないので1行でも残す
  27. preLine = line
  28. continue
  29.  
  30. if ct == 0:
  31. fo.write(line)
  32.  
  33. ct = ct + 1
  34. preLine = line
  35.  
  36. if ct == 100: # 100行に1回出力する
  37. ct = 0
  38.  
  39. fi.close()
  40. fo.close()

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

3.改良版の処理結果を見る
再度、処理結果を調べてみました。
  1. 35.08614861 136.89070723
  2. 35.08342250 136.86787278
  3. 35.05776194 136.84691778
  4. 35.06403806 136.84048584
  5.  
  6. 35.05175111 136.83802834
  7. 35.05175111 136.83802834
  8.  
  9. 35.05899417 136.87838278
  10. 35.05899417 136.87838278

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

4.小島のデータを削除する
手作業で削除するかとも思ったんですが、すぐに諦めました。さすがにデータのサイズが小さくならない原因だけあって大量に存在しています。あきらめて、2行同じ緯度経度のデータが続く箇所はフィルタするようなプログラムを作りました。(行政界の他のところで偶然そういう場所がないか、という恐れはありますがまあ少しくらい抜けてもそれに気づくほど拡大して使うことはないでしょう。もし使う必要があるなら、それはもう手作業でなんとかしてやるしかありません)
  1. #!/usr/bin/python
  2. # coding: utf-8
  3.  
  4. import sys
  5.  
  6. if __name__ == "__main__":
  7. argv = sys.argv # コマンドライン引数を格納したリストの取得
  8. argc = len(argv) # 引数の個数
  9.  
  10. # print argv
  11. # print argc
  12.  
  13. fi = open(argv[1], 'r')
  14. fo = open(argv[2], 'w')
  15.  
  16. # n行に1回出力するようにする
  17. ct = 0
  18.  
  19. preLine = ""
  20.  
  21. for line in fi:
  22. if line.strip() == "": # 島等のデータとの境界である空白行は残すようにする
  23. if (preLine.strip() != ""): # 空白行の直前のデータは残す(島の閉曲線を守るため)
  24. fo.write(preLine)
  25. fo.write(line)
  26. ct = 0 # 島のデータは少ないので1行でも残す
  27. preLine = line
  28. continue
  29.  
  30. if preLine != line:
  31. fo.write(preLine)
  32. else:
  33. preLine = ""
  34. line = ""
  35. continue
  36.  
  37. preLine = line
  38.  
  39.  
  40. fi.close()
  41. fo.close()

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

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




0 件のコメント:

コメントを投稿