ExternalFeatureAdaptor.pm 22.1 KB
Newer Older
1 2 3 4 5 6 7 8 9
#
# EnsEMBL module for Bio::EnsEMBL::External::ExternalFeatureAdaptor
#
# You may distribute this module under the same terms as perl itself

# POD documentation - main docs before the code

=head1 NAME

10 11 12 13
Bio::EnsEMBL::External::ExternalFeatureAdaptor

=head 1 SUMMARY

14 15
Allows features created externally from Ensembl in a single coordinate system
to be retrieved in several other (Ensembl-style) coordinate systems. This is
16 17
intended to be a replacement for the old 
Bio::EnsEMBL::DB::ExternalFeatureFactoryI interface.
18 19 20 21 22 23 24 25

=head1 SYNOPSIS

  $database_adaptor = 
    new Bio::EnsEMBL::DBSQL::DBAdaptor( -host   => 'kaka.sanger.ac.uk',
                                        -dbname => 'homo_sapiens_core_9_30',
                                        -pass   => 'anonymous' );

26 27
  $xf_adaptor = new ExternalFeatureAdaptorSubClass;

28
  #Connect the Ensembl core database:
29
  $xf_adaptor->db($database_adaptor);
30

31
  #get some features in vontig coords
32 33 34 35 36 37 38 39
  @feats = @{$xf_adaptor->fetch_all_by_contig_name('AC000087.2.1.42071')};

  #get some features in assembly coords
  @feats = @{$xf_adaptor->fetch_all_by_chr_start_end('X', 100000, 200000)};

  #get some features in clone coords
  @feats = @{$xf_adaptor->fetch_all_by_clone_accession('AC000087')};

40 41 42
  #Add the adaptor to the ensembl core dbadaptor (implicitly sets db attribute)
  $database_adaptor->add_ExternalFeatureAdaptor($xf_adaptor);

43 44
  #get some features in Slice coords
  $slice_adaptor = $database_adaptor->get_SliceAdaptor;
45
  $slice = $slice_adaptor->fetch_all_by_chr_start_end(1,100000,200000);
46 47
  @feats = @{$xf_adaptor->fetch_all_by_Slice($slice)};

48
  #now features can be retrieved directly from Slice
49 50 51
  @feats = @{$slice->get_all_ExternalFeatures};
  

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
=head1 DESCRIPTION

This class is intended to be used as a method of getting external features into
EnsEMBL.  To work, this class must be extended and must implement the
the coordinate_systems method.  As well, the subclass is required to implement
a single fetch method so that the external features may be retrieved.  
By implementing a single fetch_method in a single coordinate system all
of the other ExternalFeatureAdaptor fetch methods become available for 
retrieving the data in several different coordinate systems.

The coordinate_systems method should return a list of strings indicating which
coordinate system(s) have been implemented.  If a given string is returned 
from the coordinate_systems method then the corresponding fetch method must be 
implemented.  The reverse is also true: if a fetch method is implemented then
coordinate_systems must return the appropriate string in its list of return 
values.  The following are the valid coordinate system values and the 
corresponding fetch methods that must be implemented:

  COORD SYSTEM STRING   FETCH_METHOD      
  -------------------   ------------
  'ASSEMBLY'            fetch_all_by_chr_start_end
  'CLONE'               fetch_all_by_clone_accession
  'CONTIG'              fetch_all_by_contig_name
75
  'SUPERCONTIG'         fetch_all_by_supercontig_name
76 77
  'SLICE'               fetch_all_by_Slice

78 79
The objects returned by the fetch methods should be EnsEMBL or BioPerl style
Feature objects.  These objects MUST have start, end and strand methods.
80 81 82 83

Before the non-overridden ExternalFeatureAdaptor fetch methods may be called
an EnsEMBL core database adaptor must be attached to the ExternalFeatureAdaptor
.  This database adaptor is required to perform the remappings between various
84 85 86
coordinate system.  This may be done implicitly by adding the 
ExternalFeatureAdaptor to the database adaptor through a call to the 
DBAdaptor add_ExternalFeatureAdaptor method or explicitly by calling the 
87
ExternalFeatureAdaptor ensembl_db method.
88 89


90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
=head1 CONTACT

Post questions to the EnsEMBL developer list: <ensembl-dev@ebi.ac.uk>

=head1 AUTHOR

Graham McVicker

=head1 APPENDIX

The rest of the documentation details each of the object methods. 
Internal methods are usually preceded with a _

=cut

use strict;

package Bio::EnsEMBL::External::ExternalFeatureAdaptor;

109
use Bio::EnsEMBL::Utils::Exception qw(warning throw);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135


=head2 new

  Arg [1]    : none
  Example    : $xfa = new Bio::EnsEMBL::External::ExternalFeatureAdaptor;
  Description: Creates a new ExternalFeatureAdaptor object.  You may wish to
               extend this constructor and provide your own set of paremeters.
  Returntype : Bio::EnsEMBL::External::ExternalFeatureAdaptor
  Exceptions : none
  Caller     : general

=cut

sub new {
  my $class = shift;

  if(ref $class) {
    return bless {}, ref $class;
  }

  return bless {}, $class;
}



Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
136
=head2 ensembl_db
137 138

  Arg [1]    : (optional) Bio::EnsEMBL::DBSQL::DBAdaptor
Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
139
  Example    : $external_feature_adaptor->ensembl_db($new_val);
140 141 142 143 144 145 146
  Description: none
  Returntype : Bio::EnsEMBL::DBSQL::DBAdaptor
  Exceptions : none
  Caller     : internal

=cut

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
147
sub ensembl_db {
148 149 150
  my ($self, $value) = @_;

  if($value) {
151 152
    $self->{'ensembl_db'} = $value;
  }
153

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
154
  return $self->{'ensembl_db'};
155
}
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176



=head2 coordinate_systems

  Arg [1]    : none
  Example    : @implemented_coord_systems = $ext_adaptor->coordinate_systems;
  Description: ABSTRACT method. Must be implemented by all 
               ExternalFeatureAdaptor subclasses.  This method returns a list
               of coordinate systems which are implemented by the subclass. 
               A minimum of on valid coordinate system must be implemented.
               Valid coordinate systems are: 'SLICE', 'ASSEMBLY', 'CONTIG',
               and 'CLONE'.
  Returntype : list of strings
  Exceptions : none
  Caller     : internal

=cut

sub coordinate_systems {
  my $self = shift;
177 178

  throw("abstract method coordinate_systems not implemented\n");
179 180 181 182 183

  return '';
}


184 185 186 187 188 189 190 191 192 193
=head2 track_name

  Arg [1]    : none
  Example    : $track_name = $xf_adaptor->track_name;
  Description: Currently this is not really used.  In the future it may be 
               possible to have ExternalFeatures automatically displayed by
               the EnsEMBL web code.  By default this method returns 
               'External features' but you are encouraged to override this 
               method and provide your own meaningful name for the features
               your adaptor provides.  This also allows you to distinguish the
194
               type of features retrieved from Slices.  See
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
               the PODs for Bio::EnsEMBL::Slice::get_all_ExternalFeatures and 
               Bio::EnsEMBL::DBSQL::DBAdaptor::add_ExternalFeatureAdaptor 
               methods. 
  Returntype : string
  Exceptions : none
  Caller     : Bio::EnsEMBL::DBSQL::DBAdaptor::add_ExternalFeatureAdaptor

=cut

sub track_name {
  my $self = shift;

  return 'External features';
}



=head2 feature_type

  Arg [1]    : none
  Example    : $feature_type = $xf_adaptor->track_name
  Description: Currently this is not used.  In the future it may be possible
               to have ExternalFeatures automatically displayed by the EnsEMBL
               web code.  This method would then be used do determine the 
               type of glyphs used to draw the features which are returned
               from this external adaptor.
  Returntype : string
  Exceptions : none
  Caller     : none

=cut

sub feature_type {
  my $self = shift;
  
  return qw(SIMPLE);
}


234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

=head2 fetch_all_by_Slice

  Arg [1]    : Bio::EnsEMBL::Slice $slice
  Example    : @features = @{$ext_adaptor->fetch_all_by_Slice($slice)};
  Description: Retrieves all features which lie in the region defined
               by $slice in slice coordinates.  
  
               If this method is overridden then the coordinate_systems method
               must return 'SLICE' as one of its values.  

               This method will work as is (i.e. without overriding it) 
               providing at least one of the other fetch methods is overridden.
  Returntype : reference to a list of Bio::SeqFeature objects in the Slice
               coordinate system
  Exceptions : Thrown on incorrect input arguments
  Caller     : general, fetch_all_by_chr_start_end

=cut

sub fetch_all_by_Slice {
  my ($self, $slice) = @_;

  unless($slice && ref $slice && $slice->isa('Bio::EnsEMBL::Slice')) {
258
    throw("[$slice] is not a Bio::EnsEMBL::Slice");
259 260 261 262
  }

  my $out = [];

263 264 265 266
  my $csa = $self->ensembl_db->get_CoordSystemAdaptor();

  my $slice_start  = $slice->start;
  my $slice_end    = $slice->end;
267
  my $slice_strand = $slice->strand;
268 269
  my $slice_seq_region  = $slice->seq_region_name;
  my $coord_system = $slice->coord_system;
270 271

  if($self->_supported('SLICE')) {
272
    throw("ExternalFeatureAdaptor supports SLICE coordinate system" .
273
		 " but fetch_all_by_Slice not implemented");
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
  }

  my %features;
  my $from_coord_system;

  my $fetch_method;

  #
  # Get all of the features from whatever coord system they are computed in
  #
  if($self->_supported('CLONE')) {
    $fetch_method = sub {
      my $self = shift;
      my $name = shift;
      my ($acc, $ver) = split(/\./, $name);
      $self->fetch_all_by_clone_accession($acc,$ver,@_);
    };
    $from_coord_system = $csa->fetch_by_name('clone');
  } elsif($self->_supported('ASSEMBLY')) {
293
    $from_coord_system = $csa->fetch_by_name('chromosome');
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    $fetch_method = $self->can('fetch_all_by_chr_start_end');
  } elsif($self->_supported('CONTIG')) {
    $from_coord_system = $csa->fetch_by_name('contig');
    $fetch_method = $self->can('fetch_all_by_contig_name');
  } elsif($self->_supported('SUPERCONTIG')) {
    $from_coord_system = $csa->fetch_by_name('supercontig');
    $fetch_method = $self->can('fetch_all_by_supercontig_name');
  } else {
    $self->_no_valid_coord_systems();
  }

  if($from_coord_system->equals($coord_system)) {
    $features{$slice_seq_region} = &$fetch_method($self, $slice_seq_region,
                                                  $slice_start,$slice_end);
  } else {
    foreach my $segment (@{$slice->project($from_coord_system->name,
                                           $from_coord_system->version)}) {
      my ($start,$end,$pslice) = @$segment;
      $features{$pslice->seq_region_name} ||= [];
      push @{$features{$pslice->seq_region_name}},
           @{&$fetch_method($self, $pslice->seq_region_name,
                            $pslice->start(),
                            $pslice->end())};
    }
  }

  my @out;

  if(!$coord_system->equals($from_coord_system)) {             
    my $asma = $self->ensembl_db->get_AssemblyMapperAdaptor();
    my $mapper = $asma->fetch_by_CoordSystems($from_coord_system,
                                              $coord_system);
    my %slice_cache;
    my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
    my $slice_setter;

    #convert the coordinates of each of the features retrieved
    foreach my $fseq_region (keys %features) {
      my $feats = $features{$fseq_region};
      next if(!$feats);
      $slice_setter = _guess_slice_setter($feats) if(!$slice_setter);

      foreach my $f (@$feats) {
        my($sr_name, $start, $end, $strand) = 
          $mapper->fastmap($fseq_region,$f->start,$f->end,$f->strand,
                           $from_coord_system);
        
        #maps to gap
        next if(!defined($sr_name));

        #maps to unexpected seq region, probably error in the externally
        if($sr_name ne $slice_seq_region) {
          warning("Externally created Feature mapped to [$sr_name] " .
                  "which is not on requested seq_region [$slice_seq_region]");
          next;
        }

        #update the coordinates of the feature
        &$slice_setter($f,$slice);
        $f->start($start);
        $f->end($end);
        $f->strand($strand);
        push @out, $f;
      }
    }
  } else {
    #we already know the seqregion the featues are on, we just have
    #to put them on the slice
    @out = @{$features{$slice_seq_region}};
    my $slice_setter = _guess_slice_setter(\@out);

    foreach my $f (@out) {
      &$slice_setter($f,$slice);
367
    }
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
  }

  #shift the feature coordinates again if
  #the requested slice is not the full seqregion
  if($slice->start != 1 || $slice->strand != 1) {
    #convert from assembly coords to slice coords
    my($f_start, $f_end, $f_strand);
    foreach my $f (@out) {
      if($slice_strand == 1) {
        $f_start  = $f->start - $slice_start + 1;
        $f_end    = $f->end   - $slice_start + 1;
        $f_strand = $f->strand;
      } else {
        $f_start  = $slice_end - $f->end   + 1;
        $f_end    = $slice_end - $f->start + 1;
        $f_strand = $f->strand * -1;
      }
385
    
386 387 388 389
      $f->start($f_start);
      $f->end($f_end);
      $f->strand($f_strand);
    }
390 391
  }
  
392
  return \@out;
393 394 395
}
  

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
sub _guess_slice_setter {
  my $features = shift;

  #we do not know what type of features these are.  They might
  #be bioperl features or old ensembl features, hopefully they are new
  #style features.  Try to come up with a setter method for the
  #slice.

  return undef if(!@$features);

  my ($f) = @$features;

  my $slice_setter;
  foreach my $method (qw(slice contig attach_seq)) {
    last if($slice_setter = $f->can($method));
  }
    
  if(!$slice_setter) {
    if($f->can('seqname')) {
      $slice_setter = sub { $_[0]->seqname($_[1]->seq_region_name()); };
    } else {
      $slice_setter = sub{} if(!$slice_setter);
    }
  }

  return $slice_setter;
}


=head2 fetch_all_by_contig_name
426

427 428 429 430 431 432 433 434 435
  Arg [1]    : string $contig_name
  Arg [2]    : int $start (optional)
               The start of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Arg [3]    : int $end (optional) 
               The end of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Example    : @fs = @{$self->fetch_all_by_contig_name('AB00879.1.1.39436')};
  Description: Retrieves features on the contig defined by the name 
436
               $contig_name in contig coordinates.
437

438 439
               If this method is overridden then the coordinate_systems 
               method must return 'CONTIG' as one of its values. 
440

441 442 443
               This method will work as is (i.e. without being overridden) 
               providing at least one other fetch method has 
               been overridden.               
444
  Returntype : reference to a list of Bio::SeqFeature objects in the contig
445 446 447 448 449
               coordinate system.
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate_systems method returns the value 
               'CONTIG' and this method has not been overridden.
  Caller     : general, fetch_all_by_Slice
450

451 452 453 454
=cut

sub fetch_all_by_contig_name {
  my ($self, $contig_name, $start, $end) = @_;
455

456 457
  unless($contig_name) {
    throw("contig_name argument not defined");
458 459
  }

460 461 462
  if($self->_supported('CONTIG')) {
    throw("ExternalFeatureAdaptor supports CONTIG coordinate system" .
		 " but fetch_all_by_contig_name is not implemented");
463 464
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
465
  unless($self->ensembl_db) {
466
    throw('DB attribute not set.  This value must be set for the ' .
467 468
		 'ExternalFeatureAdaptor to function correctly');
  }
469

470 471 472 473
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
  my $slice = $slice_adaptor->fetch_by_region('contig', $contig_name,
                                             $start, $end);
  return $self->fetch_all_by_Slice($slice);
474 475 476 477
}



478 479 480 481 482 483 484 485 486 487
=head2 fetch_all_by_supercontig_name

  Arg [1]    : string $supercontig_name
  Arg [2]    : int $start (optional)
               The start of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Arg [3]    : int $end (optional) 
               The end of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Example    : @fs = @{$self->fetch_all_by_contig_name('NT_004321')};
488
  Description: Retrieves features on the contig defined by the name 
489
               $supercontigname in supercontig coordinates.
490 491

               If this method is overridden then the coordinate_systems 
492
               method must return 'SUPERCONTIG' as one of its values. 
493

494
               This method will work as is (i.e. without being overridden)
495
               providing at least one other fetch method has 
496 497
               been overridden.
  Returntype : reference to a list of Bio::SeqFeature objects in the contig
498 499
               coordinate system.
  Exceptions : thrown if the input argument is incorrect
500
               thrown if the coordinate_systems method returns the value
501 502
               'SUPERCONTIG' and this method has not been overridden.
  Caller     : general, fetch_all_by_Slice
503 504 505 506

=cut


507 508 509 510 511
sub fetch_all_by_supercontig_name {
  my ($self, $supercontig_name, $start, $end) = @_;

  unless($supercontig_name) {
    throw("supercontig_name argument not defined");
512 513
  }

514 515 516
  if($self->_supported('SUPERCONTIG')) {
    throw("ExternalFeatureAdaptor supports SUPERCONTIG coordinate system" .
		 " but fetch_all_by_supercontig_name is not implemented");
517 518
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
519
  unless($self->ensembl_db) {
520
    throw('DB attribute not set.  This value must be set for the ' .
521 522 523
		 'ExternalFeatureAdaptor to function correctly');
  }

524 525 526 527
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
  my $slice = $slice_adaptor->fetch_by_region('supercontig', $supercontig_name,
                                             $start, $end);
  return $self->fetch_all_by_Slice($slice);
528 529 530 531 532 533 534
}


=head2 fetch_all_by_clone_accession

  Arg [1]    : string $acc
               The EMBL accession number of the clone to fetch features from.
535 536 537
  Arg [2]    : (optional) string $ver
  Arg [3]    : (optional) int $start
  Arg [4]    : (optional) int $end
538

539 540 541
  Example    : @fs = @{$self->fetch_all_by_clone_accession('AC000093')};
  Description: Retrieves features on the clone defined by the $acc arg in 
               Clone coordinates. 
542

543
               If this method is overridden then the coordinate_systems method
544 545 546
               must return 'CLONE' as one of its values. The arguments 
               start, end, version are passed if this method is overridden and
               can optionally be used to reduce the scope of the query and 
547 548 549 550
               improve performance.

               This method will work as is - providing at least one other
               fetch method has been overridden.
551 552 553 554 555 556 557
  Returntype : reference to a list of Bio::SeqFeature objects in the Clone
               coordinate system
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate system method returns the value 'CLONE'
               and this method is not overridden.
               thrown if the coordinate systems method does not return any 
               valid values.
558
  Caller     : general, fetch_all_by_clone_accession
559 560 561 562

=cut

sub fetch_all_by_clone_accession {
563
  my ($self, $acc, $version, $start, $end) = @_;
564 565

  unless($acc) {
566
    throw("clone accession argument not defined");
567 568 569
  }

  if($self->_supported('CLONE')) {
570
    throw('ExternalFeatureAdaptor supports CLONE coordinate system ' .
571 572 573
		 'but does not implement fetch_all_by_clone_accession');
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
574
  unless($self->ensembl_db) {
575
    throw('DB attribute not set.  This value must be set for the ' .
576 577 578
		 'ExternalFeatureAdaptor to function correctly');
  }

579 580 581 582 583
  if(defined($version)) {
    $acc = "$acc.$version";
  } elsif(!$acc =~ /\./) {
    $acc = "$acc.1";
  }
584

585
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor;
586

587
  my $slice = $slice_adaptor->fetch_by_region('clone', $acc, $start, $end);
588

589
  return $self->fetch_all_by_Slice($slice);
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616
}



=head2 fetch_all_by_chr_start_end

  Arg [1]    : string $chr_name
               The name of the chromosome to retrieve features from
  Arg [2]    : int $start
               The start coordinate of the chromosomal region to retrieve
               features from.
  Arg [3]    : int $end
               The end coordinate of the chromosomal region to retrieve 
               features from.
  Example    : @features
  Description: Retrieves features on the region defined by the $chr_name,
               $start, and $end args in assembly (chromosomal) coordinates. 

               If this method is overridden then the coordinate_systems method
               must return 'ASSEMBLY' as one of its values.  

               This method will work as is (i.e. without overriding it) 
               providing at least one of the other fetch methods is overridden.
  Returntype : reference to a list of Bio::SeqFeatures 
  Exceptions : Thrown if the coordinate_systems method returns ASSEMBLY as a 
               value and this method is not overridden.  
               Thrown if any of the input arguments are incorrect
617
  Caller     : general, fetch_all_by_Slice
618 619 620 621 622 623 624

=cut

sub fetch_all_by_chr_start_end {
  my ($self, $chr_name, $start, $end) = @_;

  unless($chr_name && defined $start && defined $end && $start < $end) {
625
    throw("Incorrect start [$start] end [$end] or chr [$chr_name] arg");
626 627
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
628
  unless($self->ensembl_db) {
629
    throw('DB attribute not set.  This value must be set for the ' .
630 631 632
		 'ExternalFeatureAdaptor to function correctly');
  }

633
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
634

635 636
  my $slice = $slice_adaptor->fetch_by_region('toplevel', $chr_name, $start,
                                              $end);
637

638
  return $self->fetch_all_by_Slice($slice);
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
}


=head2 _no_valid_coord_system

  Arg [1]    : none
  Example    : none
  Description: PRIVATE method - throws an error with a descriptive message
  Returntype : none
  Exceptions : always thrown
  Caller     : internal

=cut

sub _no_valid_coord_system {
  my $self = shift;

656
  throw("This ExternalFeatureAdaptor does not support a known " .
657
		"coordinate system.\n Valid coordinate systems are: " .
658
		"[SLICE,ASSEMBLY,SUPERCONTIG,CONTIG,CLONE].\n This External Adaptor " . 
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
                "supports: [" . join(', ', $self->coordinate_systems) . "]");
}  




=head2 _supported

  Arg [1]    : string $system 
  Example    : print "CONTIG system supported" if($self->_supported('CONTIG'));
  Description: PRIVATE method. Tests if the coordinate system defined by
               the $system argument is implemented.
  Returntype : boolean
  Exceptions : none
  Caller     : internal

=cut

sub _supported {
  my ($self, $system) = @_;

  #construct the hash of supported features if it has not been already
  unless(exists $self->{_supported}) {
    $self->{_supported} = {};
    foreach my $coord_system ($self->coordinate_systems) {
      $self->{_supported}->{$coord_system} = 1;
    }
  }

  return $self->{_supported}->{$system};
}
  


1;