# # = bio/appl/iprscan/report.rb - a class for iprscan output. # # Copyright:: Copyright (C) 2006 # Mitsuteru C. Nakao # License:: The Ruby License # # # == Report classes for the iprscan program. # module Bio class Iprscan # = DESCRIPTION # Class for InterProScan report. It is used to parse results and reformat # results from (raw|xml|txt) into (html, xml, ebihtml, txt, gff3) format. # # See ftp://ftp.ebi.ac.uk/pub/software/unix/iprscan/README.html # # == USAGE # # Read a marged.txt and split each entry. # Bio::Iprscan::Report.parse_txt(File.read("marged.txt")) do |report| # report.query_id # report.matches.size # report.matches.each do |match| # match.ipr_id #=> 'IPR...' # match.ipr_description # match.method # match.accession # match.description # match.match_start # match.match_end # match.evalue # end # # report.to_gff3 # # report.to_html # end # # Bio::Iprscan::Report.parse_raw(File.read("marged.raw")) do |report| # report.class #=> Bio::Iprscan::Report # end # class Report # Entry delimiter pattern. RS = DELIMITER = "\n\/\/\n" # Qeury sequence name (entry_id). attr_accessor :query_id alias :entry_id :query_id # Qeury sequence length. attr_accessor :query_length # CRC64 checksum of query sequence. attr_accessor :crc64 # Matched InterPro motifs in Hash. Each InterPro motif have :name, # :definition, :accession and :motifs keys. And :motifs key contains # motifs in Array. Each motif have :method, :accession, :definition, # :score, :location_from and :location_to keys. attr_accessor :matches # == USAGE # Bio::Iprscan::Report.parse_raw(File.open("merged.raw")) do |report| # report # end # def self.parse_raw(io) entry = '' while line = io.gets if entry != '' and entry.split("\t").first == line.split("\t").first entry << line elsif entry != '' yield Bio::Iprscan::Report.parse_raw_entry(entry) entry = line else entry << line end end yield Bio::Iprscan::Report.parse_raw_entry(entry) if entry != '' end # Parser method for a raw formated entry. Returns a Bio::Iprscan::Report # object. def self.parse_raw_entry(str) report = self.new str.split(/\n/).each do |line| line = line.split("\t") report.matches << Match.new(:query_id => line[0], :crc64 => line[1], :query_length => line[2].to_i, :method => line[3], :accession => line[4], :description => line[5], :match_start => line[6].to_i, :match_end => line[7].to_i, :evalue => line[8], :status => line[9], :date => line[10]) if line[11] report.matches.last.ipr_id = line[11] report.matches.last.ipr_description = line[12] end report.matches.last.go_terms = line[13].scan(/(\w+ \w+\:.+? \(GO:\d+\))/).flatten if line[13] end report.query_id = report.matches.first.query_id report.query_length = report.matches.first.query_length report end # Parser method for a xml formated entry. Returns a Bio::Iprscan::Report # object. # def self.parse_xml(str) # end # Splits the entry stream. # # == Usage # # Bio::Iprscan::Report.reports_txt(File.open("merged.txt")) do |report| # report.class #=> Bio::Iprscan::Report # end # def self.parse_txt(io) io.each("\n\nSequence") do |entry| if entry =~ /Sequence$/ entry = entry.sub(/Sequence$/, '') end unless entry =~ /^Sequence/ entry = 'Sequence' + entry end yield self.parse_txt_entry(entry) end end # Parser method for a txt formated entry. Returns a Bio::Iprscan::Report # object. # def self.parse_txt_entry(str) unless str =~ /^Sequence / raise ArgumentError, "Invalid format: \n\n#{str}" end header, *matches = str.split(/\n\n/) report = self.new report.query_id = if header =~ /Sequence \"(.+)\" / then $1 else '' end report.query_length = if header =~ /length: (\d+) aa./ then $1.to_i else nil end report.crc64 = if header =~ /crc64 checksum: (\S+) / then $1 else nil end ipr_line = '' go_annotation = '' matches.each do |m| m = m.split(/\n/).map {|x| x.split(/ +/) } m.each do |match| case match[0] when 'method' when /(Molecular Function|Cellular Component|Biological Process):/ go_annotation = match[0].scan(/([MCB]\w+ \w+): (\S.+?\S) \((GO:\d+)\),*/) when 'InterPro' ipr_line = match else pos_scores = match[3].scan(/(\S)\[(\d+)-(\d+)\] (\S+) */) pos_scores.each do |pos_score| report.matches << Match.new(:ipr_id => ipr_line[1], :ipr_description => ipr_line[2], :method => match[0], :accession => match[1], :description => match[2], :evalue => pos_score[3], :status => pos_score[0], :match_start => pos_score[1].to_i, :match_end => pos_score[2].to_i, :go_terms => go_annotation) end end end end return report end # Splits entry stream. # # == Usage # Bio::Iprscan::Report.parse_ptxt(File.open("merged.txt")) do |report| # report # end def self.parse_ptxt(io) io.each("\n\/\/\n") do |entry| yield self.parse_ptxt_entry(entry) end end # Parser method for a pseudo-txt formated entry. Returns a Bio::Iprscan::Report # object. # # == Usage # # File.read("marged.txt").each(Bio::Iprscan::Report::RS) do |e| # report = Bio::Iprscan::Report.parse_ptxt_entry(e) # end # def self.parse_ptxt_entry(str) report = self.new ipr_line = '' str.split(/\n/).each do |line| line = line.split("\t") if line.size == 2 report.query_id = line[0] report.query_length = line[1].to_i elsif line.first == '//' elsif line.first == 'InterPro' ipr_line = line else startp, endp = line[4].split("-") report.matches << Match.new(:ipr_id => ipr_line[1], :ipr_description => ipr_line[2], :method => line[0], :accession => line[1], :description => line[2], :evalue => line[3], :match_start => startp.to_i, :match_end => endp.to_i) end end report end # def initialize @query_id = nil @query_length = nil @crc64 = nil @matches = [] end # Output interpro matches in the format_type. def output(format_type) case format_type when 'raw', :raw format_raw else raise NameError, "Invalid format_type." end end # def format_html # end # def format_xml # end # def format_ebixml # end # def format_txt # end def format_raw @matches.map { |match| [self.query_id, self.crc64, self.query_length, match.method_name, match.accession, match.description, match.match_start, match.match_end, match.evalue, match.status, match.date, match.ipr_id, match.ipr_description, match.go_terms.map {|x| x[0] + ': ' + x[1] + ' (' + x[2] + ')' }.join(', ') ].join("\t") }.join("\n") end # def format_gff3 # end # Returns a Hash (key as an Interpro ID and value as a Match). # # report.to_hash.each do |ipr_id, matches| # matches.each do |match| # report.matches.ipr_id == ipr_id #=> true # end # end # def to_hash unless (defined? @ipr_ids) && @ipr_ids @ipr_ids = {} @matches.each_with_index do |match, i| @ipr_ids[match.ipr_id] ||= [] @ipr_ids[match.ipr_id] << match end return @ipr_ids else return @ipr_ids end end # == Description # Container class for InterProScan matches. # # == Usage # match = Match.new(:query_id => ...) # # match.ipr_id = 'IPR001234' # match.ipr_id #=> 'IPR001234' # class Match def initialize(hash) @data = Hash.new hash.each do |key, value| @data[key.to_sym] = value end end # Date for computation. def date; @data[:date]; end # CRC64 checksum of query sequence. def crc64; @data[:crc64]; end # E-value of the match def evalue; @data[:evalue]; end # Status of the match (T for true / M for marginal). def status; @data[:status]; end # the corresponding InterPro entry (if any). def ipr_id; @data[:ipr_id]; end # the length of the sequence in AA. def length; @data[:length]; end # the analysis method launched. def method_name; @data[:method]; end # the Gene Ontology description for the InterPro entry, in "Aspect :term (ID)" format. def go_terms; @data[:go_terms]; end # Id of the input sequence. def query_id; @data[:query_id]; end # the end of the domain match. def match_end; @data[:match_end]; end # the database members entry for this match. def accession; @data[:accession]; end # the database mambers description for this match. def description; @data[:description]; end # the start of the domain match. def match_start; @data[:match_start]; end # the descriotion of the InterPro entry. def ipr_odescription; @data[:ipr_description]; end def method_missing(name, arg = nil) if arg name = name.to_s.sub(/=$/, '') @data[name.to_sym] = arg else @data[name.to_sym] end end end # class Match end # class Report end # class Iprscan end # module Bio