=begin

  $Id: Tutorial.rd.ja,v 1.5 2001/12/19 12:21:08 katayama Exp $

  Copyright (C) 2001 KATAYAMA Toshiaki <k@bioruby.org>

= BioRuby の使い方

== 塩基・アミノ酸配列を処理する (Bio::Sequence クラス)

簡単な例として、短い塩基配列 atgcatgcaaaa を使って、相補配列への変換、部
分配列の切り出し、塩基組成の計算、アミノ酸への翻訳、分子量計算などを行なっ
てみます。アミノ酸への翻訳では、必要に応じて何塩基目から翻訳を開始するか
フレームを指定したり、codontable.rb で定義されているコドンテーブルの中か
ら使用するものの番号を指定したりする事ができます。また、Sequence オブジェ
クトは Ruby の String オブジェクトを継承しているので String のメソッドを
全て使う事ができます。

    #!/usr/bin/env ruby
    
    require 'bio'
    
    seq = Bio::Sequence::NA.new("atgcatgcaaaa")
    
    puts seq				# 元の配列
    puts seq.complement			# 相補配列 (Sequence::NA オブジェクト)
    puts seq.subseq(3,8)		# 3 塩基目から 8 塩基目まで
    
    p seq.gc_percent			# GC 塩基の割合 (Float)
    p seq.composition			# 全塩基組成 (Hash)
    
    puts seq.translate			# 翻訳配列 (Sequence::AA オブジェクト)
    puts seq.translate(2)		# ２文字目から翻訳（普通は１から）
    puts seq.translate(1,11)		# 11番目のコドンテーブルを使用
    
    p seq.translate.to_a		# アミノ酸を３文字コードで表示 (Array)
    p seq.translate.to_ary		# アミノ酸を名前で表示 (Array)
    p seq.translate.composition		# アミノ酸組成 (Hash)
    p seq.translate.molecular_weight	# 分子量を計算 (Float)
    
    puts seq.complement.translate	# 相補配列の翻訳

実際には Sequence::NA オブジェクトはファイルから読み込んだ文字列から生成
したり、データベースから取得したものを使ったりします。たとえば、

    #!/usr/bin/env ruby
    
    require 'bio'
    include Bio                 # include Bio とすると、以下 Bio:: が省略できる
    
    input_seq = ARGF.read       # 引数で与えられたファイルの全行を読み込む
    
    my_naseq = Sequence::NA.new(input_seq)
    my_aaseq = my_naseq.translate
    
    puts my_aaseq

このプログラムを na2aa.rb として、以下の塩基配列

      gtggcgatctttccgaaagcgatgactggagcgaagaaccaaagcagtgacatttgtctg
      atgccgcacgtaggcctgataagacgcggacagcgtcgcatcaggcatcttgtgcaaatg
      tcggatgcggcgtga

を書いたファイル my_naseq.txt を読み込んで翻訳すると

    % ./na2aa.rb my_naseq.txt
    VAIFPKAMTGAKNQSSDICLMPHVGLIRRGQRRIRHLVQMSDAA*

のようになります。ちなみに、このくらいの例なら短くすると１行で書けます。

    % ruby -r bio -e 'p Bio::Sequence::NA.new($<.read).translate' my_naseq.txt

しかし、いちいちファイルを作るのも面倒なので、次はデータベースから必要な
情報を取得してみます。

== GenBank のパース (Bio::GenBank クラス)

GenBank 形式のファイル（元の ftp://ftp.ncbi.nih.gov/genbank/ の .seq ファ
イルでも、サブセットでもよい）が手元にあるとして、gb2fasta コマンドの真
似をして、各エントリから ID と説明文、配列を取り出して FASTA 形式に変換
してみます。ちなみに gets で使われている DELIMITER は GenBank クラスで定
義されている定数で、データベースごとに異なるエントリの区切り文字（たとえ
ば GenBank の場合は //）を覚えていなくても良いようになっています。

    #!/usr/bin/env ruby
    
    require 'bio'
    
    while entry = gets(Bio::GenBank::DELIMITER)
      gb = Bio::GenBank.new(entry)      # GenBank オブジェクト
    
      print ">#{gb.accession} "         # ACCESSION 番号
      puts gb.definition                # DEFINITION 行
      puts gb.naseq                     # 塩基配列（Sequence::NA オブジェクト）
    end

次に、GenBank の複雑な FEATURES の中もパースして、遺伝子ごとの塩基配列と
アミノ酸配列を取り出してみます。Bio::GenBank::RS は DELIMITER というのが
長いので付けてある別名です (RS は record separator の略) 。

    #!/usr/bin/env ruby
    
    require 'bio'; include Bio
    
    while entry = gets(GenBank::RS)
      # GenBank の１エントリごとに
      gb = GenBank::new(entry)

      # ACCESSION 番号と生物種名を表示
      puts "==> #{gb.accession} - #{gb.organism}"
    
      gb.features do |f|                # FEATURES の要素を一つずつ処理
        # /translation= がなければスキップ
        next unless f['translation'].length > 0
        # 遺伝子名などの情報
        puts [ f['gene'], f['product'], f['note'], f['function'] ].join(' ')
        # 塩基配列
        puts gb.naseq.splicing(f['position'])
        # アミノ酸配列（塩基配列から翻訳）
        puts gb.naseq.splicing(f['position']).translate
        # アミノ酸配列（/translation= のもの）
        puts f['translation']
      end
    end

ここで、splicing は GenBank フォーマットの位置表記（location.rb 参照）を
元に、塩基配列から exon 部分を切り出したりする強力なメソッドです。もし遺
伝子の切り出しやアミノ酸への翻訳に BioRuby のバグがあれば、最後の２行で
表示されるアミノ酸配列が異なる事になります。

この後、新しくフラットファイルを扱うラッパークラス FlatFile が実装された
ので、今なら、最初の例は次のように書き直すこともできます。

    #!/usr/bin/env ruby
    
    require 'bio'
    
    ff = Bio::FlatFile.new(Bio::GenBank, ARGF)
    ff.each_entry do |gb|
      definition = [gb.accession, gb.definition].join(" ")
      puts gb.naseq.to_fasta(definition, 60)    
    end

逆に、上記のスクリプトで作った FASTA フォーマットのファイルを読み込むに
は、

    #!/usr/bin/env ruby
    
    require 'bio'
    
    ff = Bio::FlatFile.new(Bio::FastaFormat, ARGF)
    ff.each_entry do |x|
      puts x.definition
      puts x.nalen
      puts x.naseq
    end

などとすることができます。

== FASTA による相同性検索を行う（Bio::Fasta クラス）

問い合わせ配列が FASTA 形式で入った query.pep がある時、ローカルとリモー
トで FASTA 検索を行うには、それぞれ以下のようにします。

=== ローカルの場合

FASTA がインストールされていることを確認して（コマンド名が fasta33 でパ
スが通っている場合の例で説明します）、検索対象とする FASTA 形式のデータ
ベースファイル target.pep を準備し、

    #!/usr/bin/env ruby
    
    require 'bio'
    include Bio

    # FASTA を実行する環境オブジェクトを作る（ssearch などでも良い）
    factory = Fasta.local('fasta33', ARGV.pop)

    # フラットファイルを読み込み、FastaFormat オブジェクトのリストにする
    ff = FlatFile.new(FastaFormat, ARGF)

    # １エントリずつの FastaFormat オブジェクトに対し
    ff.each do |entry|
      # '>' で始まるコメント行の内容を表示
      puts entry.definition

      # FASTA による相同性検索を実行、結果は Fasta::Report オブジェクト
      fasta_result = entry.fasta(factry)

      # ヒットしたものの中で、オーバーラップ領域が 150 残基以上のものに対し
      fasta_res.lap_over(150).each do |r|

        # FASTA の evalue と、名前、オーバーラップ領域を表示
        print "evalue #{r.evalue} : #{r.q_id} => #{r.t_id} at "
        p r.lap_at
      end
    end

ここで factory は繰り返し FASTA を実行するために、あらかじめ作っておく実
行環境です。この例では FastaFormat オブジェクトの fasta メソッドを使って
検索していますが、問い合わせ配列が１つだけの時は

    seq = ">test seq\nYQVLEEIGRGSFGSVRKVIHIPTKKLLVRKDIKYGHMNSKE"
    factory.query(seq)

のように factory に対して直接 query メソッドを呼ぶ手軽な方法もあります。

FASTA のオプションを与えたい場合、３番目の引数に hash で渡しますが、ktup 
だけはシンボル :ktup をキーにして渡して下さい。引数を取らないオプション
を渡したい場合は '-B' => '' など空文字列となる値を入れておいて下さい。

例えば ktup 値を 1 にして、ベスト 10 位以内のヒットを得る場合のオプショ
ンは、以下のようになります。

    hash = { :ktup => 1, '-b' => 10 }
    factory = Fasta.local('fasta33', 'target.pep', hash)

FastaFormat#fasta や Fasta#query メソッドの返り値は Bio::Fasta::Report
オブジェクトです。様々なメソッドで FASTA の出力結果のほぼ全てを自由に取
り出せるようになっています。

上記のスクリプトを f_search.rb という名前で作ったとすると、

    % ./f_search.rb query.pep

とすれば検索できます。先の例では、オーバーラップしている領域の長さで選択
する lap_over メソッドを使って結果を絞り込んでみましたが、検索結果から様々
な値をどのように取り出すかはスクリプト次第です。

=== リモートの場合

今のところ GenomeNet (fasta.genome.ad.jp) での検索をサポートしています。
factory の作り方と使用可能な検索対象データベースが決まっていること以外は
ほぼ同じ使い方ができます。

    program = 'fasta'
    database = 'genes'
    factory = Bio::Fasta.remote(program, database)

問い合わせがアミノ酸配列のとき：

  * 対象データベースが以下のアミノ酸配列データベースのいずれかの場合
    program は 'fasta' にします。

    * nr-aa, genes, vgenes, swissprot, swissprot-upd, pir, prf, pdbstr

  * 対象データベースが以下の核酸配列データベースのいずれかの場合
    program は 'tfasta' にします。

    * nr-nt, genbank-nonst, gbnonst-upd, dbest, dbgss,
      htgs, dbsts, embl-nonst, embnonst-upd, genes-nt,
      vgenes-nt, vgenome

問い合わせ配列が核酸配列のとき：

  * 対象データベースは以下の核酸配列データベースのいずれかで、
    program は 'fasta' にします。

    * nr-nt, genbank-nonst, gbnonst-upd, dbest, dbgss,
      htgs, dbsts, embl-nonst, embnonst-upd, genes-nt,
      vgenes-nt, vgenome, epd

== DBGET システム (Bio::DBGET クラス)

次は、ゲノムネットから DBGET を使って特定のデータベースエントリを取得す
る例です。DBGET では bfind によるエントリの検索と bget によるエントリの
取得ができます。

Bio::DBGET.bfind メソッドには、検索対象のデータベース名と検索キーワード
を与えます。例えば GenBank データベースで cyclin と kinase をキーワード
に持つエントリを検索するには、以下のようにします。

    % ruby -r bio -e 'puts Bio::DBGET.bfind("genbank cyclin kinase")'
    gb:AB010087 [AB010087] Pseudomonas aeruginosa rpsB, tsf, pyrH, f...
    gb:AF016224 [AF016224] Caenorhabditis elegans WD-40 repeat prote...
         :

結果のうち、左端に表示されているのが「データベース名:エントリ名」の表記
で、Bio::DBGET.bget メソッドを使って実際にこのエントリを取ってくることが
できます。

    % ruby -r bio -e 'puts Bio::DBGET.bget("gb:AB010087")'

これを利用して先の GenBank オブジェクトを作るには、

    #!/usr/bin/env ruby
    
    require 'bio'
    include Bio
    
    entry = Bio::DBGET.bget("gb:AB010087")
    gb = Bio::GenBank.new(entry)

のようにスクリプトを書くことになります。簡単な処理なら、

    % ruby -r bio -e 'include Bio
    > gb = GenBank.new(DBGET.bget("gb:AB010087"))
    > p gb.naseq'

などとコマンドラインで実行しても良いでしょう。

=== dbget コマンド

また、BioRuby をインストールすると、上記の例と同じことを実行するプログラ
ムである dbget コマンドも（/usr/bin/dbget などに）インストールされている
はずです。この dbget コマンドを使えば、ゲノムネットの検索、データ取得を
以下のようにコマンドラインで実行することができます。さらに、dbget に対し
以下の例のようにメソッド名でリンクを張れば、メソッド名の動作をするプログ
ラムになります。

    % dbget bget gb:AB010087

    # cd /usr/bin               ← dbget コマンドのインストール先
    # ln -s dbget bfind
    # ln -s dbget bget
    
    % bfind genbank cyclin kinase
    % bget gb:AB010087

DBGET で検索、取得できるデータベースは多数あるので、詳細は DBGET のウェ
ブページ ((<URL:http://www.genome.ad.jp/dbget/>)) を参照してください。

== KEGG::GENES のパース (Bio::KEGG::GENES, Bio::AAindex1 クラス)

次は、DBGET で KEGG の GENES データベースから古細菌 Halobacterium のバク
テリアロドプシン遺伝子 (VNG1467G) を取ってきて、アミノ酸指標データベース
である AAindex から取り出したαヘリックスの指標 (BURA740101) を使って、
幅 15 残基のウィンドウサーチをする例です。

    #!/usr/bin/env ruby
    
    require 'bio'; include Bio
    
    entry = DBGET.bget('hal:VNG1467G')
    aaseq = KEGG::GENES.new(entry).aaseq
    
    entry = DBGET.bget('aax1:BURA740101')
    helix = AAindex1.new(entry).index
    
    position = 1
    win_size = 15
    
    aaseq.window_search(win_size) do |subseq|
      score = subseq.total(helix)
      puts [ position, score ].join("\t")
      position += 1
    end

== PubMed を引いて引用文献リストを作る (Bio::PubMed クラス)

最後は、NCBI の文献データベース PubMed を検索して引用文献リストを作成す
る例です。

    #!/usr/bin/env ruby
    
    require 'bio'
    
    ARGV.each do |id|
      entry = Bio::PubMed.query(id)
      ref = Bio::MEDLINE.new(entry).reference
      puts ref.bibtex
    end

このスクリプトを pm2bibtex.rb など好きな名前で保存し、

    % ./pm2bibtex.rb 11024183 10592278 10592173

など引用したい論文の PubMed ID (PMID) を引数に並べると NCBI にアクセスし
て MEDLINE フォーマットをパースし BibTeX フォーマットに変換して出力して
くれるはずです。

ここでは bibtex メソッドで BibTeX フォーマットに変換していますが、（強調
など文字の修飾はできませんが）Nature や NAR などいくつかの雑誌のフォーマッ
トにも対応しています。

他にも、キーワードで検索する機能もあります。

    % ruby -r bio -e '
    ary = Bio::PubMed.search("bioinformatics genome")
    ary.each do |x|
      puts Bio::MEDLINE.new(x).reference.format("Nature"), "\n"
    end'

=end

