スキップしてメイン コンテンツに移動

投稿

12月, 2009の投稿を表示しています

日本全国コンビニ店舗分布地図: 高解像度インタラクティブ版

前回に引き続き今回もProcessingによる日本全国コンビニ店舗分布地図について書いてみる。前回は大きさが固定された地図で拡大・縮小や移動ができなかったので、高解像度インタラクティブ版として、それをできるようにしてみた。

まず、日本地図がPNG画像なのでこれをベクタ画像に変更する。フォーマットはSVGだ。前回と同様に「カビパン男と私」で提供されている日本地図のSVGファイルを若干加工して利用させてもらった。

次にこのSVGデータをProcessingで利用する方法について述べる。「ビジュアライジング・データ」にもSVGの利用方法(processing.candy.*)が書いてあるのだが、実はここに書いてある情報は古くて現在では使用できない。現在では、PShapeを使ってSVGを利用する。

PShape mapShape = loadShape("japan.svg");

こんな感じだ。画面の(x, y)座標に表示するにはdraw関数内で以下のように記述すればいい。

shape(mapShape, x, y);

詳しくはProcessingのリファレンスに書かれているので、下記のソースコードなどを参考にして調べてみて欲しい。

さて、これでSVG画像が利用できるようになったので、今度はこれを使って、マウスの左ボタンのドラッグで平行移動を行えるようにしてみる。やり方としてはmouseDragged関数を使う。移動したピクセル分だけ画像も移動する。mouseDragged関数内で移動分のオフセットを変数に入れるようにし、上述のshape関数でオフセット分だけ移動した位置に描画すればいい。

次に画像の拡大・縮小を行う。マウスの右ボタンのドラッグで操作する。マウスを上に移動すれば拡大、下に移動すれば縮小だ。SVG画像の縮小・拡大はscaleメソッドを使う。例えば、上記の例で元の画像を1.5倍にしたければ以下のようにする。

mapShape.scale(1.5);

scaleメソッドによる拡大・縮小は画像の位置やそのオフセットなどもちゃんと正しい位置になるようにしなければならないのだが、それらについてはソースコードを参考にして欲しい。

上記はSVG画像による日本地図の描画について説明したが、コンビニデータの描画についても位置のオフ…

Processing: 日本全国コンビニ店舗分布地図

「ビジュアライジング・データ Processingによる情報視覚化手法」を読んでみたのだが、Processingの情報処理とその視覚化がとても興味深いものだった。そこで、日本地図を使って何らかの情報を視覚化したいと考え、それならば全国に存在するコンビニ店舗の分布を調べてみようと思い、Processingで作ってみることにした。

因みに以前にも「Processingで分子動力学計算」や「Processingを使ってWebカメラを監視カメラにする」などのブログ記事を書いているように、プログラミング言語Processingはビジュアル関連で広範に応用でき、そのポテンシャルはとても大きい。

まずは、コンビニの店舗情報が必要なので、gooのコンビニ店舗検索を利用し、ここから住所情報を得ることにした。ただ、一度に検索できる件数は5,000件までなので5,000件以上存在するコンビニに対してはPythonで都道府県ごとに検索してマージした。データはHTMLで書かれているのでPythonのre.findallのパターンマッチを使って一気に必要なデータに変換した。

次に、Google MapsのHTTPリクエスト経由のジオコーディングを使って住所情報を経度・緯度に変換した。この辺もPythonを使えばちょちょいのちょいだ。以下のAPIを利用する。

http://maps.google.com/maps/geo?q=住所情報&output=json&sensor=false&key=APIキー

ただし、変換は1日につき15,000件の制限が掛かっているので4万件以上ある住所情報を取得するには3日かかることになる。もっともIPアドレスによる制限なので別のIPを使えば問題ないようだ。

日本地図上にデータを表示するためには、経度・緯度情報からXY座標に変換する必要がある。日本地図は国土地理院によるとユニバーサル横メルカトル(UTM)図法が使われているらしい。簡単に言うと世界地図でよく使われているメルカトル図法の赤道に合わせている中心線を6°ごとの経度線に合わせて作成する方法らしい。そのための変換関数をPythonで以下のように作成した。本当は縮尺の微調整が入るようなのだが、今回はそこまで厳密にする必要はないのでその辺は省いた。

def UTM(lat, lng…

CUDAで作成した分子動力学計算プログラムを書き直してみた

以前に、はじめてのCUDAプログラミングで分子動力学計算というブログ記事を書いたことがある。最近このなんちゃって分子動力学計算(MD)プログラムのソースコードを読み直してみたのだが、かなりひどい。しかも、「CUDAプログラミング」でググってみると、この記事が2番目にくる。こんないい加減なコードを参考にされたら読んだ人にも迷惑が掛かるので修正することにした。それほどCUDAに慣れているわけではないが、前回のコードよりはましだと思う。

それにしてもコードの内容がひどい。意味もなく__syncthreads()が入っているし、複数のスレッドから同じグローバルメモリに書き込みしてるし、レジスタを活用してないし、計算の順序は非効率だし、ダメダメだ。

そこでまず、CUDA Visual Profilerで関数のパフォーマンス測定を行った。因みにこのプロファイラはCUDAプログラミングツールキットに含まれているもので、CUDAでプログラミングを行うには必須だと思う。使い方は簡単で、Windowsであればcudaprof.exeを実行して、FileメニューからNew...を選び、プロジェクトの名前と場所を設定して、実行するCUDAプログラムを指定するだけだ。引数が必要ならそれも指定しておく。デフォルトでは4回実行され解析される。それぞれの関数がどれだけ時間がかかったのかプロットされるので、どこがボトルネックになっているのか一目瞭然だ。

まあ、予想していた通り、Calc関数が全体の99.8%を占めていたので、ここから修正を行った。まず、iとjを使っていたループをjだけにした。iはスレッド数で分割されていたが、ブロックと合わせてそれを消した。次に、jのループ内で不必要にグローバルメモリにアクセスしないようにした。例えばchg[i]というグローバル変数はループ外でローカル変数に入れてそれを使うようにする。あとは、できるだけ除算などの演算を減らすようにした。

次に、系全体を中心に戻す関数があるのだが、中心座標を求める部分はホスト側の関数で実装し、系全体を戻す関数のみをCUDAの関数とした。もともとこの処理は毎回やらなくてもよいものなので、指定したステップ毎に1回行うようにした。今回は100ステップに1回としている。なので、全体の処理時間から見れば無視しても良く、頑張ってすべてGPU…

C++: 構造体を格納したSTLコンテナに対してソート・探索・削除などのアルゴリズムを適用する

C++に慣れている人にとっては当たり前のことかもしれないけど、あまりC++に親しんでいない場合、構造体を格納したSTLコンテナに対してアルゴリズム<algorithm>を有効に活用していないかもしれない。そこで、構造体を格納したvectorなどのSTLコンテナでソートや探索、削除などのアルゴリズムの利用方法を書いておく。

struct A { int n; int* p; };

上記のような構造体はよく見かける形だと思う。構造体Aに整数型変数のnとポインタ型変数のpがあり、例えばnに配列の要素数、pにその配列を確保したりする。こういった構造体を以下のようにvectorなどのSTLコンテナを使って格納することは多々ある。

vector<A> A_list;

これで構造体Aをコンテナに格納できるわけだ。ところで、STLコンテナを使用する一つの理由として便利なアルゴリズムが利用できることが挙げられるだろう。sortやfindなどの定番のアルゴリズムは、それほどC++を利用していない人でもSTLを使ったことがあるのであれば知っていると思う。これらはとても便利だが、上記の構造体を入れたコンテナに対して以下のようには利用できない。

sort(A_list.begin(), A_list.end());

当たり前のことだが、どのような基準でソートするのかコンパイラには分からないからだ。なので、どのような基準でソートさせるのかを関数オブジェクトを使って教えればいい。因みに関数オブジェクトとは、operator()が定義されているクラスのことだ。

例えば構造体Aのメンバ変数であるnを基準に昇順にソートさせたいとする。その場合は以下のような関数オブジェクトを作って、sortアルゴリズムの第3引数に渡せばいい。

class LessAn { public: bool operator()(const A& a, const A& b) { return a.n < b.n; } };

sort(A_list.begin(), A_list.end(), LessAn());

たったこれだけだ。

他のアルゴリズムに対しても基本的には同じように関数オブジェクトを使えばいい。探索(find…