やはり少し頭を使って、元になる国土地理院の海岸線データの特徴を調べてみます。
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まで縮小できました。結果を以下に示します。
先日の海岸線とほとんど見た目は変わりません。よく見れば、小さな小島は消えているんですがね。