2015年7月21日火曜日

日本の海岸線データを手にいれる

レポートを書くとき、何かと使うことの多いのが地図データです。しかも緯度経度で海岸線や県境のデータがあるとベストです。(緯度経度で地点をマークして一緒にEXCELで散布図にしてやれば正確な表現ができます)
実は国土地理院では昔から公開していますが、数年前からやたら複雑な書式のxmlなので尻込みしていました。少し長い休みがあるので、重い腰をあげてデータ整理でもしてみましょう。

1.海岸線データを入手する
ぐぐれば簡単に見つかります。DLするとき何に使う?とか簡単なアンケートに答えないといけませんが、「趣味」の項目もありますから特に気張らずに。(ただ、ライセンス的にフリーというわけではないので注意はしてください。個人目的、研究用等に使うならご自由にという程度です)
データは県ごとに分かれています。

2.xmlフォーマット
各県ごとにデータが分かれています。しかも、県の中でも行政界ごとにxmlのタグが分けられているようです。以下に例を示します。

  <gml:LineStringSegment>
   <gml:posList>
35.55061306 140.11532166
35.55081833 140.11538084
35.55206806 140.11517666

xmlのタグ、<gml:posList>で識別されています。数字は一目で緯度経度とわかります。(国土地理院なので、今は当然世界測地系です)

3.海岸線データを取り出す
テキストエディタで取り出してもいいんですが、なにせ数があります。こちらは単に日本地図が描きたいだけなんですが、きちんと県別、さらに行政界毎にデータがタグで分離されているため、テキストエディタで手作業でやってたら死にます。
とりあえず、xmlなので、以下のプログラムでこのタグ部分だけ抽出してやります。

# coding: utf-8

import xml.dom.minidom

if __name__ == "__main__":

 dom = xml.dom.minidom.parse("sample.xml")

 for line in dom.getElementsByTagName("gml:posList"):
  print line.firstChild.data

以下の様な感じで海岸線のデータだけ標準出力にでてきますので、それをファイルにリダイレクトしてやります。

35.55061306 140.11532166
35.55081833 140.11538084
35.55206806 140.11517666
35.55243944 140.11512389
35.55278833 140.11507416

4.データの間引き
さてこうしてできた海岸線のデータですが、単に数値の羅列ですがなんと100MB強あります!県毎にsheetを分ければなんとか日本の海岸線を散布図で描けますが、一つのファイルにまとめてしまうと、サイズが(行数が)大きくEXCELが扱えないといってきます。どうせそんな細かいところまで見ないので、データの間引きをします。そのために用意したプログラムを以下に示します。

#!/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

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

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

  ct = ct + 1

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

 fi.close()
 fo.close()

今回は起動時に入力ファイル、出力ファイルを読むようにしました。あと間引く時、元のデータでは行政界毎、及び島毎に空行が入っていました。ここを無視して間引いいてしまうと、小さな島だとデータがなくなってしまいかねません。ちょっとだけ工夫しました。間引く数は実際に試して実験です。結局、10分の1(約10MB)にしないとまともにEXCELは動きませんでした。使うPC環境にもよりますが、もう少し間引いた方がいい気がします。またどうせかなりの縮尺で使うつもりなので、こだわって島のでデータを消さないようにしました。小さな島は消したいんですが、属性として地名は入っているんですが、それが島かどうかは人間が判断してやらないといけません。(GISデータは最後は人力で編集しないと、いいデータにはなりませんね(>_<))

5.完成
以下に実際に作成した日本(白)地図を示します。


使うときは例で示したように、別途示したい位置の緯度経度のデータを用意して、データ系列を追加してやります。注意が必要なのは、普通にやると追加したデータのグラフも散布図の折れ線になってしまいます。単にX-Yの座標だけの散布図にしたい場合が多いでしょうから、その時はデータ系列を追加してから、追加したデータを選択し、グラフの種類を変えてやります。(「複合グラフ」といいます)


2015年6月21日日曜日

g++における、getline()の戻り値について

cのときからテキストファイルを読み込むときによく使っていたのがgetline()でした。

ssize_t getline(char** , size_t , FILE* )

1行ずつ読込、戻り値に読み込んだ文字数が返ってくるため、ファイルの最後までいくと読めないので、文字数0が返ってきました。それを使って、最後まで読んだかをチェックするのが普通でした。

while ( getline(line, 256, fp) !=0 )

こんな感じです。c++になるとifstreamで同じ関数があり、確か最初(20年くらい前)は同じ仕様だったと思います。ずっとそう思っていました…

Macのxcodeで既存のlinuxで作成したプログラムをコンパイルしようとすると、どうしてもこのgetline()でエラーがでて、ずっと悩んでいましたが今日やっと理由がわかりました。c++でのgetline()の戻り値はifstream自身でした。
つまり、読込に成功したら"true"、最後までいき失敗したら"false"を返すようになってました。
でもこれまでlinuxの方では、0とかNULLで比較していても何もいってこなかったんで気付きませんでしたが、本当は以下のようにチェックすべきでした。

while ( fp.getline(line, 256))

linuxの方は昔のcの実装がboolがなくて、unsigned intでやれ、という指定だったためそれとの互換性を考えていたようです。しかしmacは厳密にチェックするようになったため、エラーにしているようです。さて、既存の遺産をどうするか注意しないと。


2015年6月13日土曜日

既存のgit管理されたCプログラムをeclipseで開発

久しぶりにちょっとした備忘録です。

1.概要
2.eclipseで操作する前の状態
3.eclipseで操作する状態
4.やった方が感じがいいこと

こんな感じで進めていきたいと思います。

1.概要
他のPC、或いは既にプロジェクトが少し進んでいてそれがgit管理されています。そこに参加した、或いは最初はソースコードを書いていただけで、実際のコンパイルをこれから始めるという状況です。
Linuxを想定しますが、eclipse-CDTだとC/C++プロジェクトを作成でき、しかも今はGit管理パッケージが最初から入っています。(数年前はGit管理パッケージが最初は入っていなくて、いちいちEGitを後から入れたりして大変でした)

話を簡単にするために以下の状況を想定します。

・ソースはgithub等のリポジトリにあるわけではなく、何故かローカルでPCに入れてあります。(分散リポジトリなんで、簡単に実現できます)
・~/ProgWork/work以下にgit管理されたソースが入っています。
・そこにはmain.cだけが入っています。
・当然、~/ProgWork/workには .git ディレクトリがあります。

つまり、このgit管理されたものをeclipseで開発を(gitを使いながら)継続したいというわけです。

2.eclipseで操作する前の状態
とりあえずデフォルトの状態として、eclipseの作業ディレクトリは、$HOME/workspaceとしておきます。最初はもちろん何もプロジェクトがなく、空っぽとします。(注:でも最新のeclipseだと、workspace/RemoteSystemTemFilesなんてディレクトリができていました。何でしょこれ?)

3.eclipseで操作する状態
やることは以下の通りです。

(1)eclipseでFileメニューから"Import"を選択する。
(2)選択Dialogが表示されます。その中に、"Git"があります。"Projects from Git"を選択してNextします。
(3)次のDialogで"Existing local repository"というのがでてきますので、これを選択します。(注:ちなみに通常は外部のgithub等からプロジェクトをとってきますから、もう一つの"Clone URI"を選択します。こっちのやり方は以前にも書きましたのでここでは省略します。)
(4)ここで、~/ProgWork/work/.gitを選択します。
(5)後はproject wizardに進みますので、そのまま作業を進めればeclipseで開発が続けれます。
(6)ただこれではプロジェクトを作っただけで、まだ肝心のソースファイルがプロジェクトに入っていません。Fileメニューで作ったプロジェクトにソースファイルを追加してやります。
(7)ただこれだけではまだ、このプロジェクトはGit管理できません。eclipseのTeamメニューでもいつものGit関係のコマンドがでてきません。Teamメニューから"Share project"をしてやる必要があります。

ところでこの状態でディレクトリの状態はどうなっているんでしょう?ここからは実は2通りあります。今回ブログを書くにあたって実験してたら、2通りの状態になってしまいました。どちらが正しい状態かはわかりませんが、どちらも動くようなのでたまたまなのでしょう。

"sample"というc/c++のプロジェクトを作りましたが、~/ProgWork/work/sampleというディレクトリが作成されました。ビルドしたバイナリはここにできます。
問題は、eclipseが管理する、".project"なんですが、これが~/ProgWork/work/sampleにできる場合と、eclipseのデフォルトの、~/workspace/sampleにできる場合の2通りにわかれました。
どちらの場合でも、結局元のソースは~/ProgWork/work/以下にあり、eclipseからは普通に操作できますし、gitでcommitもできます。
(実は、自分はここでworkspace/sample以下にコピーが作成されてしまい、eclipse独自のgit管理に入ってしまうかと予想していましたが、そんなことはありませんでした^^;)

4.やった方が感じがいいこと
さて、残る問題はeclipseによって勝手に作成される、~/ProgWork/work/sampleというディレクトリです。これがgit管理下には入っていませんから、よくgitから文句を言われます。
こんなときは、~/ProgWork/work/.gitignoreファイルを作り、そこに"sample/"と文字列を追加しておけば、gitはそれは自分の管轄外と思ってくれて無視してくれます。
ただ、さらにいうと今度は".gitignore"も管理に入れろとgitは文句をいってきます。これを.gitignoreに含めるかは、宗教の問題になってきます。会社などで同じ開発環境で作業しているなら、.gitiginore自体も共有すべきだというのが、通常の考え方なんだそうです。ただまあこれは好みの問題で、自分の様に個人で遊んでいる場合には.gitiginoreに自身も含めてしまっています。
(だって、"git status"で毎回なんか文句言われると気になるから)


2015年5月24日日曜日

テーブルデータのグラフ表示

さてCouchDBを使って、テーブルデータを扱うhtmlはできましたが、まだ表だけです。やはりここはグラフ表示できないと使い物になりません。そこでjCanvasを使ってグラフ表示できるようにしてみました。 まずデータの読込です。

ここで1つデータを追加します。
とまあ、順調にできました。
いつもならここでコードを参考に載せるところですが、機能的にまだあまりに不足している部分があるので、今回はパスします。こういう汎用的なものなら、以下の機能が欲しいところです。
・グラフを描画するcanvas要素のサイズに応じて描画。
・グラフ描画の際の上下左右のマージンをパラメータ化。
・あと、グラフの軸に目盛りが欲しい!
はっきりいって「とりあえず描画できるのを確認した」というレベルのコードしかまだできていません。( ;´Д`)まだ使い物になるかわかりませんが、少し様子をみて使い物になりそうなら、コードを作り込んでからまたブログに載せます。



2015年5月5日火曜日

CouchDB テーブルデータを表示/更新

さて単純なデータの表示/更新はできました。続いてテーブルデータです。例としては高度による静圧を取り上げます。とりあえず、出来た結果の表示例を以下に示します。(注:うっかり例には「標準大気圧テーブル」と書いてしまいましたが、正確には標準大気圧を元にした静圧のテーブルです。後で気づきました。(^_^;))


これの元になったCouchDBのドキュメントは以下です。

{ "_id": "StaticPressure", 
 "_rev": "16-482692fb61559cf3ad7224021b093d63", 
 "name": "StaticPressure", 
 "value": { "StaticPressure": [ { "Alt": 0, "P": 10332 }, { "Alt": 1, "P": 9167 }, { "Alt": 2, "P": 8106 } ] }, 
 "unit": "Alt[km],P[kgf/m2]" }

取り扱いたいデータは、"value"項にあるObjectのArrayです。(後にデータの追加を説明しますが、最初はこれもjson形式だと勘違いしていましたが、正確には違うんですね。そのためjsonのデータハンドリングが使えず、JavaScriptのObjectのデータとして取り扱います。つまりObjectのArrayがjsonの一つのデータとして格納されている形になっています)

「読込」ボタンで動くJacaScriptを以下に示します。


   var url = 'http://localhost:5984/environment/StaticPressure';
   var json;
   var json_part; // 静圧テーブルデータ部分(正確に言うと狭義のJSONとは違う)


   function exec() {
    // データの読み込み
    $.ajax({
     type: "GET",
     url: url,
     dataType:'json',
    }).done(function(data) {
     json = data;
     json_part = data.value;

     for (var i=0; i<json_part.StaticPressure.length; i++) {
      // 表(table)の最後の行に追加
      $('#table1 > tbody:last').append('<tr><td>'+ json_part.StaticPressure[i].Alt +'</td><td>'+ json_part.StaticPressure[i].P +'</td></tr>');     
     }

    }).fail(function(xhr, textStatus, errorThrown){
     alert('error!!');
     console.log("NG:" + xhr.status);
     console.log("NG:" + textStatus.status);
     $('#msg').append("失敗しました");
    });

   }


#table1というidのtableタグがhtml側に用意してあり、そこに読み込んだ静圧テーブルのデータを1行づつ追加していくだけです。

次に「追加」を実装します。最初の例に既に「読込」の右横に2個の入力フィールドとともに準備してあります。ここに、「0.5」「1000」という 値を入れて「追加」してみます。
無事データが一行追加されました。「追加」ボタンの実装を以下に示します。
function add() {
 var newAlt = parseFloat( $('#inputAlt').val() );
 var newPressure = parseFloat( $('#inputPressure').val() );

 // 入力データを追加する(単純に検索する)
 for (var i=0; i<json_part.StaticPressure.length; i++) {

  if (json_part.StaticPressure[i].Alt <= newAlt) {
   continue;
  }

  var newdata = {};
  newdata.Alt = newAlt;
  newdata.P = newPressure;

  // 表(table)のi行に追加
  $('#table1 tr').eq(i).after('<tr><td>'+ newdata.Alt +'</td><td>'+ newdata.P +'</td></tr>');

  // 静圧テーブルデータにも追加
  // 第1引数:変更を加えるindex
  // 第2引数:第1引数から難行のObjectを削除するか指定
  // 第3引数:変更として追懐したいObject
  json_part.StaticPressure.splice(i, 0, newdata);

  break;    
}

今回は注意点が2箇所あります。
①17行目でtableに値を追加しています。前回はappend( )を使いましたが、今回はafter( )を使いました。理由がわかりませんが、append( )だとテーブルの形が崩れたからです。(右横に1列追加される感じになってしまいました)この辺はもう少し勉強が必要です。
②23行目で実際のメモリ中のデータにも挿入しています。最初にも書きましたが、てっきりこれがjson形式のデータと思い込んでいたので、pushやなんか使おうとしたんですが、エラーばかり返されてきました。JavaScriptのObjectというデータ形式の中で、特にハンドリングしやすいようにフォーマットを決められたのがjsonとのことで、JavaScript内部のメモリでの持ち方はどちらも同じですが、使う関数が違います。splice( )と呼ばれるArrayに対する操作を行う関数を使っています。

ところで最初に「読込」時、テーブルデーを扱いやすくするため、json内部のvalueの部分だけjson_partという変数に代入してました。これまさしくポインタの代入で、「追加」の方でjsn_partにデータを追加したら、しっかしjsonの方にも反映されていました。(この辺りはjavaと同じで、変数は基本ポインタで値を保持しているようです)
後はこの新しいデータをCouchDBに戻してやるのと、せっかくテーブルデータなのでグラフが欲しいところですが、それはまた次回に。



2015年4月30日木曜日

CouchDB データを表示/更新するサンプル

ずいぶん前回から時間が空いてしまいました。余裕がなかったのもありますが、一番大きいのがこのBloggerでHTMLのソースを表示する方法が中々わからなかったのが一番大きい理由です。prettyprint使っても、どうしても内部のhtmlを本物のタグと解釈してしまうんです。結局そのままブログにペーストするのは諦めて、「偽の」HTMLに変換してからprettyprintすることにしました。(一手間増えるのと、ブログ編集中に確認がしづらいのでこの方法はどうしても嫌だったんですが、どうもこれしかなさそうです。あと変換ツールの問題なのか、シングルクオート、ダブルクオートの前にバックスラッシュが入ってしまいます。手作業で少しは削除しましたが、途中でめげました。) さて以下がサンプルで作成したHTMLの表示例です。
地球半径をCouchDBに登録したものです。「読み込み」ボタンでCouchDBからデータを読み込み表示し、「変更」でvalueに入力されている値をCouchDBに書き込みます。デバッグ用に、一番下に読み込んだり、書き込んだりするjson形式のデータを表示しています。
以下がそのサンプルです。(注:クオートの前にバックスラッシュが入ってしまっているのは無視してください。)

<!DOCTYPE html>
<html lang="ja">
 <head>
  <meta charset="UTF-8">
  <title>HTML5</title>
  <script src="jquery-1.11.2.min.js"></script>
  <script src="stringify.js"></script>
 </head>
 <body>
  <p>Hello Ajax, couchdb データ更新をします</p>
  <input type="button" value="読み込み" onclick="readCouch('msg');">
  <input type="button" value="変更" onclick="change()">
  <!-- <TEXTAREA cols="40" rows="6" id="texts" wrap="on"></TEXTAREA> -->
  <script>
   var url;
   url = 'http://localhost:5984/environment/Radius';
   var json;

   function readCouch(id) {
    var target = document.getElementById(id);

    $('#texts').text("これから読みます:");
    $('#msg').append("これから読みます:</br>");

    $.ajax({
     type: "GET",
     url: url,
     dataType:'json',
    }).done(function(data) {
     // alert('読み込み');
     json = data;
     $(\'#id_text\').val(data._id);
     $(\'#name_text\').val(data.name);
     $(\'#value_text\').val(data.value.toString());
     $(\'#unit_text\').val(data.unit);

     var str = $.stringify(data);
     $(\'#msg\').append(str);
    }).fail(function(xhr, textStatus, errorThrown){
     alert(\'error!!\');
     console.log(\"NG:\" + xhr.status);
     console.log(\"NG:\" + textStatus.status);
     $(\'#msg\').append(\"失敗しました</br>\");
    });

    $(\'#msg\').empty();
    $(\'#msg\').append(\"うまくいった?</br>\");

   }

   function change() {
    json.value = parseFloat($(\'#value_text\').val());
    var jsonStr = JSON.stringify(json);

    $.ajax({
     type: \"PUT\",
     url: url,
     data: jsonStr,
     dataType:\'json\',
    }).done(function(data) {

     var str = $.stringify(data);
     $(\'#msg\').append(str);
    }).fail(function(xhr, textStatus, errorThrown){
     alert(\'error!!\');
     console.log(\"NG:\" + xhr.status);
     console.log(\"NG:\" + textStatus.status);
     $(\'#msg\').append(\"失敗しました</br>\");
    });
   }
  </script>
  <br>
  <table border=\"0\">
   <tr>
    <td align=\"right\"><label>id : </label></td>
    <td><input type=\"text\" id=\"id_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>name : </label></td>
    <td><input type=\"text\" id=\"name_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>value : </label></td>
    <td><input type=\"text\" id=\"value_text\"></td>
   </tr>
   <tr>
    <td align=\"right\"><label>unit : </label></td>
    <td><input type=\"text\" id=\"unit_text\"></td>
   </tr>
  </table>
  <br>
  <p id=\"msg\"></p>
 </body>
</html>

これまでGUIでのデータ入出力画面をMotifやらViduslaStuioで組んできましたが、こっちの方がOSを選ばないので汎用性が高いです。(ただ2次元のグラフも表示したい、3次元のグラフィックが欲しい、とか言われるとHTML5のCanvsタグが必要になってくるので、現時点ではブラウザを選んでしまうのが悩ましいところです。)

追記:
ところで上記サンプルでは更新したいのは"value"だけなのに、ドキュメント全体のjsonデータをCouchDBに送信しています。これって無駄が多くない?と思い調べてみると、jsonStrを作るstringify( )で第2引数に特定のjsonデータだけを指定してやればjsonStrもそれだけが作れることがわかりました。
これはいい!と思って早速試してみたんですが、CouchDBのデータを管理するのがドキュメント単位で、さらにそれにrev番号まで付いています。つまり変更したい部分だけのjsonStrを送信してしまうと、残りの部分がなくなったドキュメントになってしまいます。ちょっとこれではうまくありません。あきらめるしかないようです。(あまりでかいドキュメントが必要になるようなデータベース構成にすると処理時間が問題になってきます)

2015年2月23日月曜日

Xcodeでgithubを利用

ネットでよく見る話題ですが、サクッといくこともあれば、苦労している記事もあります。自分の場合は苦労しました ^^;) どうもsshキーの登録を手動でしないといけないようなんですが、その辺が詳しく書いてあるものがありません。基本的にはコマンドラインで一回手動でやれば自動的にキーは記録してくれますが、ちょっとメモしておきます。(まあ、こんなのは昔のeclipseでもよくありました。少し前から全部GUIでできるようになったと思います。)

1.Xcodeでプロジェクトの作成
とりあえず何かプロジェクトを作成しましょう。あと重要なことですが、最初にローカルでGit管理するかという問い合わせがひっそりとあります。(デフォルトがオフです)これのチェックを入れておくことを忘れずに。(後からGit管理する方法もあるようですが、Xcodeのバージョンがあがるとどうなるか分からないので、面倒くさければ新規に作り直した方が早いと思います)

2.remoteリポジトリの登録
まずgithubに管理用のリポジトリを作成しておきます。(これ重要。いろんなツールを見てきましたが、新規に作成するリポジトリまで作成してくれる統合ツールは見た事ありません。おそらくgithubが新規リポジトリ作成のAPI(URL経由のね)は作ってないんでしょう。そうしないと、いたずらされかねませんしね。)
XcodeのSourceControlからConfigureで、remoteとしてgithubの先ほど作成したリポジトリを登録しておきます。

3.最初のcommitをローカルにする
とりあえず、ローカルのリポジトリにcommitしておきます。

4,remoteにpushする
ここが一番の難関です。Xcodeから行おうとすると、いかにもIDとパスワードを聞いてきて、うまくいきそうに見えますが失敗します。最初はプロジェクト以下の.gitにsshパスワードが入っていませんから。
ツールを使ってもいいんですが、最初だけは手動でgitコマンドでpushします。

$ git push -u origin master

このときgithubのユーザID、パスワードを聞かれますがここでsshキーが.git以下に登録されますから、あとはXcodeでも自由に操作できるようになります。

毎回思うことですが、gitって便利だけどどうしてもコマンドラインからの入力が避けれないな〜。(コマンドラインでbranchの操作とか、差分見ようと思うと地獄なんですが、どうして公式にはGUI作ってくれないのか。そのあたりはLinusさんの主義なんですかね。GUIあたりは周りに任して、自分は本質の部分だけに集中するとか。自分はコマンドライン、そんなに気にならないほうだからいいけど、若いもんは使ってくれないよ。emacsで編集、make、debugまでするのは会社ではもう自分だけじゃなかろうか。今時のは、統合開発ツールあるのが当たり前と思ってるし。自分としてはツールの裏で何動いているのかわからない方が怖いんだが。)