情報科学概論
2000.6.27


  1. 本日の作業内容

  2. データ形式変換

    先週より現在学習した範囲で作成可能な実用的なスクリプトを実際に体験して、基本的なプログラミング技術を習得するように方針が変わった。今回も引き続き、少ない行数で簡単に記述できてしかも実際に研究上で使用するデータ形式の変更スクリプトについて学習する。

    今回扱うのは、マトリックス状に並んだデータを表計算のために列形式に変換するスクリプトである。教科書の本日の範囲である配列に関して、種々の技術を使うことになるので教科書のp.91-92を参照すること。

    さて、実際の作業であるが、初めに目的を示す。下に示すのは、原子間力顕微鏡によるハードディスク表面の構造、および、記録ビットの状態を磁気力顕微鏡で観察した例である。

    原子間力顕微鏡に関してはこちらのページに説明してあるが、要は、非常に細かい表面の凹凸(高さが原子の大きさ程度)を観察するための顕微鏡である。このような顕微鏡は走査プローブ顕微鏡と呼ばれ、小さな針が試料の表面を2次元的にスキャン(走査)することにより凹凸の情報を得ている。観察画像は高さを視覚的に見るために、色付けをされ凹凸がそれらしく見えるように加工される。その際に、この例では縦横に256個ずつ65536個のデータを集め、画像として合成している。このデータはコンピュータにより処理され、各種の解析が行えるが、取り込んだデータは縦256行、横256列のマトリックス状に並んだ構成となっている。

    データを処理するためには、画像データをx,y,zの3次元の情報として並べ直し、縦に65536行、横に3列の形式へと変更する必要がある。理由は、表計算を行うためのデータ形式がそのようになっていることが多いことである。また、自分で別の環境でプロットし直す場合でも、やはりx,y,zのデータの並びとなっている方が都合がよい。例えば、下に示す図は縄手が試作している装置で作製したCoの微小ドットの原子間力顕微鏡と磁気力顕微鏡の画像である。

    この左側の原子間力顕微鏡による表面の凹凸の状態をよりビジュアルにわかりやすく見るために角度を少し変えてみる。例えば、水平方向に45°試料を回転させた後、さらに斜め45°上方から俯瞰するようにアレンジすると、下の図のようになり、構造の把握を行いやすい。

    上のように画像を自由に扱うためには先程述べたようなデータの並びを変更する必要がある。本日の作業はそのような目的を達するためのデータ変換スクリプトの学習である。


  3. 今日の例題

    上であげたような実際の測定データではデータのサイズが大きすぎて例題に向かないので、ここでは、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
    

    このマトリックスは、一番上の行はy座標が0のデータを表し、下に行くにつれてy座標が1ずつ増え、また、一番左の列はx座標が0を意味し、右に行くとともに、xが1ずつ増える。すなわち、データの位置が座標を表し、データの中身はz座標の値(高さ)を表現している。このデータをxyz.txtとして用意しておく。

    次に、スクリプト本体であるが、以下のようになる。

    例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
    
    スクリプトの構成は以下のようになっている。

    • まず初めにdataという名前の配列を用意する。
    • データのサイズを定義する。(10×10)
    • データファイルから1行ずつ読み込んで、その行の値を配列に変換する。
    • その配列を先ほど定義したdataに追加していくことによりデータ数が100の配列を作る。
    • 次に出力を行うが、現在配列に入っているデータは、z(x,y)を座標がx,yのときのzの値とすると、

      [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として実行権限を与え、

    $ ./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
    

    例1と異なっているのは、gets()で読み込んだ行をそのままdataに追加すると、勝手に入れ子の配列を作ってくれることを利用している点である。すなわち、whileループの1度目の動作でy=0の行をそのまま[[z(0,0), z(1,0), z(2,0), ..., z(9,0)]]というように読み込み、2度目では[[...], [z(0,1), z(1,1), z(2,1), ..., z(9,1)]という配列を作る。そのような作業を繰り返すことにより2次元的に扱える配列が作成できるので、出力の形式が変わっている。print文自体はこちらの方がすっきりしている。

    ただし、この場合のデータの列は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
    

    配列の要素を代入するところで、その座標との関連を明示的に行っていることがわかる。その結果、配列はdata[x][y]形式にできる。


  4. 課題

    授業の進み具合によって課題を課すのでアナウンスに注意すること。


  5. 解答例

    次のページに5.30の課題に関する解答例を示す。


ページの先頭に戻る

目次ページに戻る