先週より現在学習した範囲で作成可能な実用的なスクリプトを実際に体験して、基本的なプログラミング技術を習得するように方針が変わった。今回も引き続き、少ない行数で簡単に記述できてしかも実際に研究上で使用するデータ形式の変更スクリプトについて学習する。
今回扱うのは、マトリックス状に並んだデータを表計算のために列形式に変換するスクリプトである。教科書の本日の範囲である配列に関して、種々の技術を使うことになるので教科書のp.91-92を参照すること。
さて、実際の作業であるが、初めに目的を示す。下に示すのは、原子間力顕微鏡によるハードディスク表面の構造、および、記録ビットの状態を磁気力顕微鏡で観察した例である。
原子間力顕微鏡に関してはこちらのページに説明してあるが、要は、非常に細かい表面の凹凸(高さが原子の大きさ程度)を観察するための顕微鏡である。このような顕微鏡は走査プローブ顕微鏡と呼ばれ、小さな針が試料の表面を2次元的にスキャン(走査)することにより凹凸の情報を得ている。観察画像は高さを視覚的に見るために、色付けをされ凹凸がそれらしく見えるように加工される。その際に、この例では縦横に256個ずつ65536個のデータを集め、画像として合成している。このデータはコンピュータにより処理され、各種の解析が行えるが、取り込んだデータは縦256行、横256列のマトリックス状に並んだ構成となっている。
データを処理するためには、画像データをx,y,zの3次元の情報として並べ直し、縦に65536行、横に3列の形式へと変更する必要がある。理由は、表計算を行うためのデータ形式がそのようになっていることが多いことである。また、自分で別の環境でプロットし直す場合でも、やはりx,y,zのデータの並びとなっている方が都合がよい。例えば、下に示す図は縄手が試作している装置で作製したCoの微小ドットの原子間力顕微鏡と磁気力顕微鏡の画像である。
この左側の原子間力顕微鏡による表面の凹凸の状態をよりビジュアルにわかりやすく見るために角度を少し変えてみる。例えば、水平方向に45°試料を回転させた後、さらに斜め45°上方から俯瞰するようにアレンジすると、下の図のようになり、構造の把握を行いやすい。
上のように画像を自由に扱うためには先程述べたようなデータの並びを変更する必要がある。本日の作業はそのような目的を達するためのデータ変換スクリプトの学習である。
上であげたような実際の測定データではデータのサイズが大きすぎて例題に向かないので、ここでは、10×10のデータ列に対して変換作業を行う。元のデータファイルは例えば次のようなものであるとする。
1 1 2 2 2 3 3 2 2 1 1 2 3 3 3 4 4 3 3 2 2 3 4 4 4 5 5 4 4 3 3 5 6 7 7 8 8 7 6 5 3 6 8 9 10 12 12 10 8 7 3 8 10 13 16 18 19 16 12 10 2 7 12 17 19 22 23 20 16 10 2 7 12 17 20 21 21 18 13 10 1 6 11 16 18 20 19 15 10 9 1 4 8 12 13 13 12 10 7 5
次に、スクリプト本体であるが、以下のようになる。
例1
#!/usr/bin/ruby data = [] x = 10; y = 10 while line = gets() ary_line = line.split(/\s+/) for j in 0..y-1 data << ary_line[j] end end for j in 0..x-1 for k in 0..y-1 print j, "\t", k, "\t", data[j+10*k], "\n" print "\n" if k == y-1 # for gnuplot end endスクリプトの構成は以下のようになっている。
[z(0,0), z(1,0), z(2,0), z(3,0), ..., z(8,9), z(9,9)]
のような順序で100個並んでいるので、一つの行がx座標、y座標、zの値というデータ列を作るために出力形式を変更する。すなわち、10個おきにデータをピックアップしていくと同じx座標のデータとなるので、例のようになっている。
$ ./3-d.rb xyz.txt
とすると、データが変換されたことが確認できる。なお、上のスクリプトで
print "\n" if k == y-1 # for gnuplot
という行はGNUPLOTでグラフ化するために空行が必要なので付けている。Excelなどへ移す場合には必要はない。(ただし、Excelにはまともな3Dグラフ作成機能は無い。)
ついでにここでGNUPLOTに関して少し動作を確認してみよう。まずは、先ほどのデータを保存する必要があるので、
$ ./3-d.rb xyz.txt > data.txt
などとして、ファイルに結果を保存する。次に、Ktermなどから
$ gnuplot
とコマンドを入力すると、GNUPLOTが起動し、プロンプトがgnuplot>に変わる。その状態で、
gnuplot> set parametric
とした後で、
gnuplot> splot 'data.txt' with linespoints
とすると、グラフを3次元表示できる。視点を変えることも可能で、例えば、
gnuplot> set view 75,45,,,
のようにすると、画面の平面に横にx軸、縦にy軸、画面垂直方向手前にz軸という構成に対して、まず、x軸の周りに75°回転し、そのあとで、z軸の周りに45°回転した眺めとなるので、再び
gnuplot> splot 'data.txt' with linespoints
とすると、先ほどとは異なった角度からの眺めが得られる。詳しくは、「論文作成術」のp.39を参照のこと。
さて、今の例では、配列はデータが一列に100個並んだ形式であった。しかし、直感的にデータを扱うためには配列自体が2次元の方が好ましい。例えば、x,yに関してzの値はdata[x][y]のように指定できる方がわかりやすい。そのような配列は教科書のp.91にあるような「入れ子」により実現できる。その場合のスクリプトは以下のように上の例とは少し異なったものとなる。
例2
#!/usr/bin/ruby data = [] x = 10; y = 10 while line = gets() data << line.split(/\s+/) end for j in 0..x-1 for k in 0..y-1 print j, "\t", k, "\t", data[k][j], "\n" print "\n" if k == y-1 # for gnuplot end end
ただし、この場合のデータの列はdata[y][x]という並びになっていることに注意しておく必要がある。
すっきりとdata[x][y]という形式にするためには上のような配列要素の自動追加ではなく自分で明示的に配列の大きさを定義し、代入する必要がある。それを実現するスクリプトを以下に示すが、ここでは、教科書のp.102とp.133で出てくるcollectというメソッドを利用している。
例3
#!/usr/bin/ruby x = 10; y = 10 i = 0 data = (0...x).collect{Array.new(0,y)} while line = gets() ary_line = line.split(/\s+/) for j in 0..y-1 data[j][i] = ary_line[j] end i += 1 end for j in 0..x-1 for k in 0..y-1 print j, "\t", k, "\t", data[j][k], "\n" print "\n" if k == y-1 # for gnuplot end end
授業の進み具合によって課題を課すのでアナウンスに注意すること。
次のページに5.30の課題に関する解答例を示す。