~ubuntu-branches/ubuntu/trusty/bioperl/trusty

« back to all changes in this revision

Viewing changes to Bio/DB/Taxonomy/flatfile.pm

  • Committer: Package Import Robot
  • Author(s): Charles Plessy
  • Date: 2013-09-22 13:39:48 UTC
  • mfrom: (3.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20130922133948-c6z62zegjyp7ztou
Tags: 1.6.922-1
* New upstream release.
* Replaces and Breaks grinder (<< 0.5.3-3~) because of overlaping contents.
  Closes: #722910
* Stop Replacing and Breaking bioperl ( << 1.6.9 ): not needed anymore. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
 
14
14
=head1 NAME
15
15
 
16
 
Bio::DB::Taxonomy::flatfile - An implementation of Bio::DB::Taxonomy
17
 
which uses local flat files
 
16
Bio::DB::Taxonomy::flatfile - Use the NCBI taxonomy from local indexed flat files
18
17
 
19
18
=head1 SYNOPSIS
20
19
 
21
20
  use Bio::DB::Taxonomy;
22
21
 
23
 
  my $db = Bio::DB::Taxonomy->new(-source => 'flatfile',
24
 
                                  -nodesfile => $nodesfile,
25
 
                                  -namesfile => $namefile);
 
22
  my $db = Bio::DB::Taxonomy->new(-source    => 'flatfile' ,
 
23
                                  -nodesfile => 'nodes.dmp',
 
24
                                  -namesfile => 'names.dmp');
26
25
 
27
26
=head1 DESCRIPTION
28
27
 
29
 
This is an implementation which uses local flat files and the DB_File
30
 
module RECNO data structures to manage a local copy of the NCBI
31
 
Taxonomy database.
 
28
This is an implementation of Bio::DB::Taxonomy which stores and accesses the
 
29
NCBI taxonomy using flat files stored locally on disk and indexed using the
 
30
DB_File module RECNO data structure for fast retrieval.
32
31
 
33
 
Required database files can be obtained from
 
32
The required database files, nodes.dmp and names.dmp can be obtained from
34
33
ftp://ftp.ncbi.nih.gov/pub/taxonomy/taxdump.tar.gz
35
34
 
36
35
=head1 FEEDBACK
81
80
# Let the code begin...
82
81
 
83
82
package Bio::DB::Taxonomy::flatfile;
84
 
use vars qw($DEFAULT_INDEX_DIR $DEFAULT_NODE_INDEX          $DEFAULT_NAME2ID_INDEX $DEFAULT_ID2NAME_INDEX
85
 
            $NCBI_TAXONOMY_HOSTNAME $DEFAULT_PARENT_INDEX
86
 
            $NCBI_TAXONOMY_FILE @DIVISIONS);
 
83
 
 
84
use vars qw($DEFAULT_INDEX_DIR $DEFAULT_NODE_INDEX $DEFAULT_NAME2ID_INDEX
 
85
            $DEFAULT_ID2NAME_INDEX $DEFAULT_PARENT_INDEX @DIVISIONS);
 
86
 
87
87
use strict;
 
88
use DB_File;
88
89
use Bio::Taxon;
89
 
use DB_File;
 
90
use File::Spec::Functions;
90
91
 
91
92
use constant SEPARATOR => ':';
92
93
 
93
 
$DEFAULT_INDEX_DIR = '/tmp';
94
 
$DEFAULT_NODE_INDEX = 'nodes';
 
94
$DEFAULT_INDEX_DIR     = $Bio::Root::IO::TEMPDIR; # /tmp
 
95
$DEFAULT_NODE_INDEX    = 'nodes';
95
96
$DEFAULT_NAME2ID_INDEX = 'names2id';
96
97
$DEFAULT_ID2NAME_INDEX = 'id2names';
97
 
$DEFAULT_PARENT_INDEX = 'parents';
98
 
$NCBI_TAXONOMY_HOSTNAME = 'ftp.ncbi.nih.gov';
99
 
$NCBI_TAXONOMY_FILE = '/pub/taxonomy/taxdump.tar.gz';
 
98
$DEFAULT_PARENT_INDEX  = 'parents';
100
99
 
101
100
$DB_BTREE->{'flags'} = R_DUP; # allow duplicate values in DB_File BTREEs
102
101
 
124
123
 Args    : -directory => name of directory where index files should be created
125
124
           -nodesfile => name of file containing nodes (nodes.dmp from NCBI)
126
125
           -namesfile => name of the file containing names(names.dmp from NCBI)
127
 
           -force     => 1 replace current indexes even if they exist
 
126
           -force     => 1 to replace current indexes even if they exist
128
127
 
129
128
=cut
130
129
 
131
130
sub new {
132
 
  my($class,@args) = @_;
 
131
  my($class, @args) = @_;
133
132
 
134
133
  my $self = $class->SUPER::new(@args);
135
 
  my ($dir,$nodesfile,$namesfile,$force) = $self->_rearrange([qw
136
 
          (DIRECTORY NODESFILE NAMESFILE FORCE)], @args);
 
134
  my ($dir,$nodesfile,$namesfile,$force) =
 
135
      $self->_rearrange([qw(DIRECTORY NODESFILE NAMESFILE FORCE)], @args);
137
136
  
138
137
  $self->index_directory($dir || $DEFAULT_INDEX_DIR);
139
138
  if ( $nodesfile ) {
140
 
          $self->_build_index($nodesfile,$namesfile,$force);
 
139
          $self->_build_index($nodesfile,$namesfile,$force);
141
140
  }
142
141
 
143
142
  $self->_db_connect;
144
143
  return $self;
145
144
}
146
145
 
147
 
=head2 Bio::DB::Taxonomy Interface implementation
 
146
 
 
147
=head2 Bio::DB::Taxonomy interface implementation
 
148
 
 
149
=head2 get_num_taxa
 
150
 
 
151
 Title   : get_num_taxa
 
152
 Usage   : my $num = $db->get_num_taxa();
 
153
 Function: Get the number of taxa stored in the database.
 
154
 Returns : A number
 
155
 Args    : None
148
156
 
149
157
=cut
150
158
 
 
159
sub get_num_taxa {
 
160
    my ($self) = @_;
 
161
    if (not exists $self->{_num_taxa}) {
 
162
        my $num = 0;
 
163
        while ( my ($parent, undef) = each %{$self->{_parent2children}} ) {
 
164
           $num++;
 
165
        }
 
166
        $self->{_num_taxa} = $num;
 
167
    }
 
168
    return $self->{_num_taxa};
 
169
}
 
170
 
 
171
 
151
172
=head2 get_taxon
152
173
 
153
174
 Title   : get_taxon
206
227
 
207
228
*get_Taxonomy_Node = \&get_taxon;
208
229
 
 
230
 
209
231
=head2 get_taxonids
210
232
 
211
233
 Title   : get_taxonids
235
257
 
236
258
*get_taxonid = \&get_taxonids;
237
259
 
 
260
 
238
261
=head2 get_Children_Taxids
239
262
 
240
263
 Title   : get_Children_Taxids
247
270
=cut
248
271
 
249
272
sub get_Children_Taxids {
250
 
   my ($self,$node) = @_;
 
273
   my ($self, $node) = @_;
251
274
   $self->warn("get_Children_Taxids is deprecated, use each_Descendent instead");
252
275
   my $id;
253
276
   if( ref($node) ) {
254
277
       if( $node->can('object_id') ) {
255
 
           $id = $node->object_id;
 
278
           $id = $node->object_id;
256
279
       } elsif( $node->can('ncbi_taxid') ) {
257
 
           $id = $node->ncbi_taxid;
 
280
           $id = $node->ncbi_taxid;
258
281
       } else { 
259
 
           $self->warn("Don't know how to extract a taxon id from the object of type ".ref($node)."\n");
260
 
           return;
 
282
           $self->warn("Don't know how to extract a taxon id from the object of type ".ref($node)."\n");
 
283
           return;
261
284
       }
262
285
   } else { $id = $node }
263
286
   my @vals = $self->{'_parentbtree'}->get_dup($id);
264
287
   return @vals;
265
288
}
266
289
 
 
290
 
267
291
=head2 ancestor
268
292
 
269
293
 Title   : ancestor
285
309
    if (length($node)) {
286
310
        my (undef, $parent_id) = split(SEPARATOR,$node);
287
311
        $parent_id || return;
288
 
                $parent_id eq $id && return; # one of the roots
 
312
        $parent_id eq $id && return; # one of the roots
289
313
        return $self->get_taxon($parent_id);
290
314
    }
291
315
    return;
292
316
}
293
317
 
 
318
 
294
319
=head2 each_Descendent
295
320
 
296
321
 Title   : each_Descendent
307
332
    $self->throw("Must supply a Bio::Taxon") unless ref($taxon) && $taxon->isa('Bio::Taxon');
308
333
    $self->throw("The supplied Taxon must belong to this database") unless $taxon->db_handle && $taxon->db_handle eq $self;
309
334
    my $id = $taxon->id || $self->throw("The supplied Taxon is missing its id!");
310
 
        
 
335
 
311
336
    my @desc_ids = $self->{'_parentbtree'}->get_dup($id);
312
337
    my @descs;
313
338
    foreach my $desc_id (@desc_ids) {
314
339
        push(@descs, $self->get_taxon($desc_id) || next);
315
340
    }
316
 
        return @descs;
 
341
    return @descs;
317
342
}
318
343
 
 
344
 
319
345
=head2 Helper methods 
320
346
 
321
347
=cut
322
348
 
323
349
# internal method which does the indexing
324
350
sub _build_index {
325
 
    my ($self,$nodesfile,$namesfile,$force) = @_;
 
351
    my ($self, $nodesfile, $namesfile, $force) = @_;
326
352
    
327
 
    my ($dir) = ($self->index_directory);
328
 
    my $nodeindex = "$dir/$DEFAULT_NODE_INDEX";
329
 
    my $name2idindex = "$dir/$DEFAULT_NAME2ID_INDEX";
330
 
    my $id2nameindex = "$dir/$DEFAULT_ID2NAME_INDEX";
331
 
    my $parent2childindex = "$dir/$DEFAULT_PARENT_INDEX";
332
 
    $self->{'_nodes'}    = [];
333
 
    $self->{'_id2name'} = [];
334
 
    $self->{'_name2id'} = {};
 
353
    my $dir = $self->index_directory;
 
354
    my $nodeindex         = catfile($dir, $DEFAULT_NODE_INDEX);
 
355
    my $name2idindex      = catfile($dir, $DEFAULT_NAME2ID_INDEX);
 
356
    my $id2nameindex      = catfile($dir, $DEFAULT_ID2NAME_INDEX);
 
357
    my $parent2childindex = catfile($dir, $DEFAULT_PARENT_INDEX);
 
358
    $self->{'_nodes'}           = [];
 
359
    $self->{'_id2name'}         = [];
 
360
    $self->{'_name2id'}         = {};
335
361
    $self->{'_parent2children'} = {};
336
362
    
337
363
    if (! -e $nodeindex || $force) {
342
368
        unlink $nodeindex;
343
369
        unlink $parent2childindex;
344
370
        my $nh = tie ( @nodes, 'DB_File', $nodeindex, O_RDWR|O_CREAT, 0644, $DB_RECNO) || 
345
 
            $self->throw("Cannot open file '$nodeindex': $!");  
 
371
            $self->throw("Cannot open file '$nodeindex': $!");
346
372
        my $btree = tie( %parent2children, 'DB_File', $parent2childindex, O_RDWR|O_CREAT, 0644, $DB_BTREE) || 
347
 
            $self->throw("Cannot open file '$parent2childindex': $!");  
 
373
            $self->throw("Cannot tie to file '$parent2childindex': $!");
348
374
        
349
375
        while (<NODES>) {
 
376
            next if /^$/;
350
377
            chomp;
351
378
            my ($taxid,$parent,$rank,$code,$divid,undef,$gen_code,undef,$mito) = split(/\t\|\t/,$_);
352
 
                        # don't include the fake root node 'root' with id 1; we essentially have multiple roots here
353
 
                        next if $taxid == 1;
354
 
                        if ($parent == 1) {
355
 
                                $parent = $taxid;
356
 
                        }
357
 
                        
 
379
            # don't include the fake root node 'root' with id 1; we essentially have multiple roots here
 
380
            next if $taxid == 1;
 
381
            if ($parent == 1) {
 
382
                $parent = $taxid;
 
383
            }
 
384
 
358
385
            # keep this stringified
359
386
            $nodes[$taxid] = join(SEPARATOR, ($taxid,$parent,$rank,$code,$divid,$gen_code,$mito));
360
387
            $btree->put($parent,$taxid);
374
401
        unlink $id2nameindex;
375
402
        my (@id2name,%name2id);
376
403
        my $idh = tie (@id2name, 'DB_File', $id2nameindex, O_RDWR|O_CREAT, 0644, $DB_RECNO) || 
377
 
            $self->throw("Cannot open file '$id2nameindex': $!");
 
404
            $self->throw("Cannot tie to file '$id2nameindex': $!");
378
405
        my $nameh = tie ( %name2id, 'DB_File', $name2idindex, O_RDWR|O_CREAT, 0644, $DB_HASH) || 
379
 
            $self->throw("Cannot open file '$name2idindex': $!");
 
406
            $self->throw("Cannot tie to file '$name2idindex': $!");
380
407
        
381
408
        while (<NAMES>) {
382
 
            chomp;          
 
409
            next if /^$/;
 
410
            chomp; 
383
411
            my ($taxid, $name, $unique_name, $class) = split(/\t\|\t/,$_);
384
 
                        # don't include the fake root node 'root' or 'all' with id 1
385
 
                        next if $taxid == 1;
386
 
                        
 
412
            # don't include the fake root node 'root' or 'all' with id 1
 
413
            next if $taxid == 1;
 
414
 
387
415
            $class =~ s/\s+\|\s*$//;
388
416
            my $lc_name = lc($name);
389
417
            my $orig_name = $name;
435
463
    }
436
464
}
437
465
 
 
466
 
438
467
# connect the internal db handle
439
468
sub _db_connect {
440
469
    my $self = shift;
441
470
    return if $self->{'_initialized'};
442
 
    
443
 
    $self->{'_nodes'}   = [];
444
 
    $self->{'_id2name'} = [];
445
 
    $self->{'_name2id'} = {};
446
 
    
447
 
    my ($dir) = ($self->index_directory);
448
 
    my $nodeindex = "$dir/$DEFAULT_NODE_INDEX";
449
 
    my $name2idindex = "$dir/$DEFAULT_NAME2ID_INDEX";
450
 
    my $id2nameindex = "$dir/$DEFAULT_ID2NAME_INDEX";
451
 
    my $parent2childindex = "$dir/$DEFAULT_PARENT_INDEX";
 
471
 
 
472
    my $dir = $self->index_directory;
 
473
    my $nodeindex         = catfile($dir, $DEFAULT_NODE_INDEX);
 
474
    my $name2idindex      = catfile($dir, $DEFAULT_NAME2ID_INDEX);
 
475
    my $id2nameindex      = catfile($dir, $DEFAULT_ID2NAME_INDEX);
 
476
    my $parent2childindex = catfile($dir, $DEFAULT_PARENT_INDEX);
 
477
    $self->{'_nodes'}           = [];
 
478
    $self->{'_id2name'}         = [];
 
479
    $self->{'_name2id'}         = {};
 
480
    $self->{'_parent2children'} = {};
452
481
    
453
482
    if( ! -e $nodeindex ||
454
 
        ! -e $name2idindex || 
455
 
        ! -e $id2nameindex ) {
456
 
        $self->warn("Index files have not been created");
457
 
        return 0;
 
483
        ! -e $name2idindex || 
 
484
        ! -e $id2nameindex ) {
 
485
        $self->warn("Index files have not been created");
 
486
        return 0;
458
487
    }
459
488
    tie ( @{$self->{'_nodes'}}, 'DB_File', $nodeindex, O_RDWR,undef, $DB_RECNO) 
460
 
        || $self->throw("$! $nodeindex");
 
489
        || $self->throw("$! $nodeindex");
461
490
    tie (@{$self->{'_id2name'}}, 'DB_File', $id2nameindex,O_RDWR, undef, 
462
 
         $DB_RECNO) || $self->throw("$! $id2nameindex");
 
491
        $DB_RECNO) || $self->throw("$! $id2nameindex");
463
492
    
464
493
    tie ( %{$self->{'_name2id'}}, 'DB_File', $name2idindex, O_RDWR,undef, 
465
 
          $DB_HASH) || $self->throw("$! $name2idindex");
 
494
        $DB_HASH) || $self->throw("$! $name2idindex");
466
495
    $self->{'_parentbtree'} = tie( %{$self->{'_parent2children'}},
467
 
                                   'DB_File', $parent2childindex, 
468
 
                                   O_RDWR, 0644, $DB_BTREE);
469
 
    $self->{'_initialized'}  = 1;
 
496
                                   'DB_File', $parent2childindex, 
 
497
                                   O_RDWR, 0644, $DB_BTREE);
 
498
 
 
499
    $self->{'_initialized'} = 1;
470
500
}
471
501
 
472
502
 
481
511
 
482
512
=cut
483
513
 
 
514
 
484
515
sub index_directory {
485
516
    my $self = shift;
486
517
    return $self->{'index_directory'} = shift if @_;
487
518
    return $self->{'index_directory'};
488
519
}
489
520
 
 
521
 
490
522
1;