[Bioperl-l] Bio::*Taxonomy* changes
Chris Fields
cjfields at uiuc.edu
Tue Jul 25 15:36:40 UTC 2006
> On Jul 25, 2006, at 3:05 AM, Sendu Bala wrote:
>
> > [...]
> > ## the fully-manual way
> > my $species = new Bio::Species;
> > my $node = new Bio::Taxonomy::Node(-name => 'Saccharomyces
> > cerevisiae',
> > -rank => 'species', -object_id
> > => 1,
> > -parent_id => 2);
>
> If this is meant as an example for the use cases I enumerated, then
> you wouldn't have the parent_id from a Genbank file. However, you
> didn't have that before either, so no problem.
>
> > my $n2 = new Bio::Taxonomy::Node(-name => 'Saccharomyces',
> > -object_id => 2, -parent_id => 3);
> > # (no assumption that 'Saccharomyces' is the genus, so rank()
> > undefined)
>
> I think in a confident parse you want to assign 'genus' if there's
> little doubt, for example 'Saccharomyces cerevisiae'. Not sure
> whether there are weird viri whose names look innocuous but in
> reality the name doesn't follow binomial convention.
>
> > my $n3 = [etc]
> > $species->add_node($node);
> > $species->add_node($n2);
>
> I know why you are doing this, but seeing this people will hit a
> mental snag. You should listen to Chris' refusal to see the sense in
> this as an indication that many people down the road won't see the
> sense either.
Thanks for pointing that out. I think there is only a small, fundamental
difference in our views here. I'm trying to view this as an outsider would,
a biologist not familiar with the Bioperl class structure. I understand
what Sendu's trying to accomplish but it's really confusing to someone not
familiar with what Bio::Species is.
Hilmar, you had pointed out several times that Bio::Species and
Bio::Taxonomy shouldn't directly intermingle.
My original thought for genbank.pm _read_GenBank_Species() was this, copied
and pasted from my local genbank.pm. It's sort of extreme, but it passes
tests just fine.
sub _read_GenBank_Species {
my( $self,$buffer) = @_;
$_ = $$buffer;
my @organelles = qw(plastid chloroplast mitochondrion);
my( $source_data, $common_name, @class, $ns_name, $organelle,
$source_flag, $sci_name, $abbr );
while (defined($_) || defined($_ = $self->_readline())) {
# de-HTMLify (links that may be encountered here don't
contain
# escaped '>', so a simple-minded approach suffices)
s/<[^>]+>//g;
if ( /^SOURCE\s+(.*)/o ) {
$source_data = $1;
$source_data =~ s/\.$//; # remove trailing dot
# does it have a GenBank common name in parentheses?
$common_name = $source_data =~ m{\((.*)\)}xms;
# organelle? If we find additional odd ones,
# add to @organelle
$organelle = grep { $_ =~ $source_data }
@organelles;
$source_flag = 1;
} elsif ( /^\s{2}ORGANISM\s+(.*)/o ) {
$sci_name = $1;
$source_flag = 0;
} elsif ($source_flag) { # no ORGANISM
$common_name .= $source_data;
$common_name =~ s/\n//g;
$common_name =~ s/\s+/ /g;
$source_flag = 0;
} elsif ( /^\s+(.+)/o ) { # lineage information
my $line = $1;
# only split on ';' or '.' so that classification
# that is 2 words will still get matched, use
# map() to remove trailing/leading spaces
push(@class, map { s/^\s+//; s/\s+$//; $_; }
split /[;\.]+/, $line)
if ( $line =~ /(;|\.)/ );
} else { # reach end of GenBank tax info
last;
}
$_ = undef; # Empty $_ to trigger read of next line
}
$$buffer = $_;
@class = reverse @class;
my $make = Bio::Taxonomy::Node->new();
$make->common_name( $common_name ) if $common_name;
$make->scientific_name($sci_name) if $sci_name;
# could use SimpleValue objs here instead
$make->classification( @class ) if @class;
$make->organelle($organelle) if $organelle;
return $make;
}
# back in next_seq...grab the TaxID from 'source'
# seqfeature
# could check organelle() here as well
# add taxon_id from source if available
if($species && ($feat->primary_tag eq 'source') &&
$feat->has_tag('db_xref') && (! $species->ncbi_taxid())) {
foreach my $tagval ($feat->get_tag_values('db_xref')) {
if(index($tagval,"taxon:") == 0) {
$species->ncbi_taxid(substr($tagval,6));
last;
}
}
}
In other words, remove the extra parsing of genus() species() subspecies
etc. All GenBank sequences have a node represented in NCBI's tax database
(I checked it out). Even plasmids, unknowns, environmental samples.
Chris
> So instead, make the logical model in your design more obvious, which
> I think ultimately will help maintainability as well. For example:
>
> my $taxonomy = Bio::Taxonomy->new();
> my $node = new Bio::Taxonomy::Node(-name => 'Saccharomyces cerevisiae',
> -rank => 'species', -object_id
> => 1,
> -parent_id => 2);
> my $n2 = new Bio::Taxonomy::Node(-name => 'Saccharomyces',
> -object_id => 2, -parent_id => 3);
> $taxonomy->add_node($node);
> $taxonomy->add_node($n2);
>
> my $species = Bio::Species->new(-lineage => $taxonomy);
> print $species->binomial();
> print $species->genus();
> # this may trigger a lookup if a taxonomy db handle has been set, e.g.:
> # $taxonomy->db_handle(Bio::DB::Taxonomy->new(-source => 'entrez'));
> print $species->classification();
>
>
> > [etc]
> >
> > ## Using a factory without db access
> > # assume that Bio::Taxonomy::GenbankFactory implements
> > # some modified Bio::Taxonomy::FactoryI
> > my $factory = Bio::Taxonomy::GenbankFactory->new();
> > my $species = $factory->generate(-classification => ['Saccharomyces
> > cerevisiae', 'Saccharomyces',
> > 'Saccharomycetaceae' ...]);
> > # the generate() method above just does the fully-manual way for you
>
> Except the method name would be create_object(), the parameter would
> be a hash ref, and the return value would be a Bio::TaxonomyI
> compliant object:
>
> my $taxonomy = $factory->create_object({-classification =>
> ['Saccharomyces
> cerevisiae', 'Saccharomyces',
> 'Saccharomycetaceae' ...]});
> my $species = Bio::Species->new(-lineage => $taxonomy);
>
>
> >
> > ## Using a factory with db access
> > # assume that Bio::Taxonomy::EntrezFactory implements some
> > # modified Bio::Taxonomy::FactoryI and uses Bio::DB::Taxonomy::entrez
> > # to get the nodes
> > my $factory = Bio::Taxonomy::EntrezFactory->new();
>
> The logic where to do a lookup on should not be duplicated here. It
> only belongs under Bio::DB::Taxonomy::*.
>
> > my $species = $factory->fetch(-scientifc_name => 'Saccharomyces
> > cerevisiae');
>
> Likewise, use the methods defined in Bio::DB::Taxonomy, and again,
> the return type is Bio::Taxonomy, which you would pass to
> Bio::Species->new().
>
> -hilmar
> --
> ===========================================================
> : Hilmar Lapp -:- Durham, NC -:- hlapp at gmx dot net :
> ===========================================================
>
>
>
>
>
> _______________________________________________
> Bioperl-l mailing list
> Bioperl-l at lists.open-bio.org
> http://lists.open-bio.org/mailman/listinfo/bioperl-l
More information about the Bioperl-l
mailing list