Archive Ensembl HomeArchive Ensembl Home
Feature.pm
Go to the documentation of this file.
00001 =head1 LICENSE
00002 
00003   Copyright (c) 1999-2012 The European Bioinformatics Institute and
00004   Genome Research Limited.  All rights reserved.
00005 
00006   This software is distributed under a modified Apache license.
00007   For license details, please see
00008 
00009     http://www.ensembl.org/info/about/code_licence.html
00010 
00011 =head1 CONTACT
00012 
00013   Please email comments or questions to the public Ensembl
00014   developers list at <dev@ensembl.org>.
00015 
00016   Questions may also be sent to the Ensembl help desk at
00017   <helpdesk@ensembl.org>.
00018 
00019 =cut
00020 
00021 =head1 NAME
00022 
00023 Bio::EnsEMBL::Feature - Ensembl specific sequence feature.
00024 
00025 =head1 SYNOPSIS
00026 
00027     my $feat = new Bio::EnsEMBL::Feature(
00028       -start  => 100,
00029       -end    => 220,
00030       -strand => -1,
00031       -slice  => $slice -analysis => $analysis
00032     );
00033 
00034     my $start  = $feat->start();
00035     my $end    = $feat->end();
00036     my $strand = $feat->strand();
00037 
00038     # Move the feature to the chromosomal coordinate system
00039     $feature = $feature->transform('chromosome');
00040 
00041     # Move the feature to a different slice (possibly on another coord
00042     # system)
00043     $feature = $feature->transfer($new_slice);
00044 
00045     # Project the feature onto another coordinate system possibly across
00046     # boundaries:
00047     @projection = @{ $feature->project('contig') };
00048 
00049     # Change the start, end, and strand of the feature in place
00050     $feature->move( $new_start, $new_end, $new_strand );
00051 
00052 =head1 DESCRIPTION
00053 
00054 This is the Base feature class from which all Ensembl features inherit.
00055 It provides a bare minimum functionality that all features require.  It
00056 basically describes a location on a sequence in an arbitrary coordinate
00057 system.
00058 
00059 =head1 METHODS
00060 
00061 =cut
00062 
00063 
00064 package Bio::EnsEMBL::Feature;
00065 
00066 use strict;
00067 use warnings;
00068 
00069 use Bio::EnsEMBL::Storable;
00070 use Bio::EnsEMBL::Utils::Argument qw(rearrange);
00071 use Bio::EnsEMBL::Utils::Exception qw(throw deprecate warning);
00072 use Bio::EnsEMBL::Utils::Scalar qw(check_ref assert_ref);
00073 use Bio::EnsEMBL::Slice;
00074 use Bio::EnsEMBL::StrainSlice;
00075 use vars qw(@ISA);
00076 
00077 use Scalar::Util qw(weaken isweak);
00078 
00079 @ISA = qw(Bio::EnsEMBL::Storable);
00080 
00081 
00082 =head2 new
00083 
00084   Arg [-SLICE]: Bio::EnsEMBL::SLice - Represents the sequence that this
00085                 feature is on. The coordinates of the created feature are
00086                 relative to the start of the slice.
00087   Arg [-START]: The start coordinate of this feature relative to the start
00088                 of the slice it is sitting on.  Coordinates start at 1 and
00089                 are inclusive.
00090   Arg [-END]  : The end coordinate of this feature relative to the start of
00091                 the slice it is sitting on.  Coordinates start at 1 and are
00092                 inclusive.
00093   Arg [-STRAND]: The orientation of this feature.  Valid values are 1,-1,0.
00094   Arg [-SEQNAME] : A seqname to be used instead of the default name of the 
00095                 of the slice.  Useful for features that do not have an 
00096                 attached slice such as protein features.
00097   Arg [-dbID]   : (optional) internal database id
00098   Arg [-ADAPTOR]: (optional) Bio::EnsEMBL::DBSQL::BaseAdaptor
00099   Example    : $feature = Bio::EnsEMBL::Feature->new(-start    => 1, 
00100                                                      -end      => 100,
00101                                                      -strand   => 1,
00102                                                      -slice    => $slice,
00103                                                      -analysis => $analysis);
00104   Description: Constructs a new Bio::EnsEMBL::Feature.  Generally subclasses
00105                of this method are instantiated, rather than this class itself.
00106   Returntype : Bio::EnsEMBL::Feature
00107   Exceptions : Thrown on invalid -SLICE, -ANALYSIS, -STRAND ,-ADAPTOR arguments
00108   Caller     : general, subclass constructors
00109   Status     : Stable
00110 
00111 =cut
00112 
00113 
00114 sub new {
00115   my $caller = shift;
00116 
00117   my $class = ref($caller) || $caller;
00118   my ( $start, $end, $strand, $slice, $analysis,$seqname, $dbID, $adaptor ) =
00119       rearrange(['START','END','STRAND','SLICE','ANALYSIS', 'SEQNAME',
00120          'DBID', 'ADAPTOR'], @_);   
00121   if($slice) {
00122     if(!ref($slice) || !($slice->isa('Bio::EnsEMBL::Slice') or $slice->isa('Bio::EnsEMBL::LRGSlice')) ) {
00123       throw('-SLICE argument must be a Bio::EnsEMBL::Slice not '.$slice);
00124     }
00125   }
00126 
00127   if($analysis) {
00128     if(!ref($analysis) || !$analysis->isa('Bio::EnsEMBL::Analysis')) {
00129       throw('-ANALYSIS argument must be a Bio::EnsEMBL::Analysis not '.
00130             $analysis);
00131     }
00132   }
00133 
00134   if(defined($strand)) {
00135     if(!($strand == 1) && !($strand == -1) && !($strand == 0)) {
00136       throw('-STRAND argument must be 1, -1, or 0');
00137     }
00138   }
00139 
00140   if(defined($start) && defined($end)) {
00141       if (($start =~ /\d+/) && ($end =~ /\d+/)) {
00142       if($end+1 < $start) {
00143           throw('Start must be less than or equal to end+1');
00144       }
00145       } else {
00146           throw('Start and end must be integers');
00147       }
00148   }
00149 
00150   my $self =  bless({'start'    => $start,
00151                 'end'      => $end,
00152                 'strand'   => $strand,
00153                 'slice'    => $slice,
00154                 'analysis' => $analysis,
00155                 'seqname'  => $seqname,
00156                 'dbID'     => $dbID}, $class);
00157 
00158   $self->adaptor($adaptor);
00159   return $self;
00160 }
00161 
00162 
00163 =head2 new_fast
00164 
00165   Arg [1]    : hashref to be blessed
00166   Description: Construct a new Bio::EnsEMBL::Feature using the hashref.
00167   Exceptions : none
00168   Returntype : Bio::EnsEMBL::Feature
00169   Caller     : general, subclass constructors
00170   Status     : Stable
00171 
00172 =cut
00173 
00174 
00175 sub new_fast {
00176   my $class = shift;
00177   my $hashref = shift;
00178   my $self = bless $hashref, $class;
00179   weaken($self->{adaptor})  if ( ! isweak($self->{adaptor}) );
00180   return $self;
00181 }
00182 
00183 =head2 start
00184 
00185   Arg [1]    : (optional) int $start
00186                The start of this feature relative to the start of the slice
00187                that it is on.
00188   Example    : $start = $feat->start()
00189   Description: Getter/Setter for the start of this feature relative to the 
00190                start of the slice it is on.  Note that negative values, or
00191                values exceeding the length of the slice are permitted.
00192                Start must be less than or equal to the end regardless of the 
00193                strand. Coordinate values start at 1 and are inclusive.
00194   Returntype : int
00195   Exceptions : none
00196   Caller     : general
00197   Status     : Stable
00198 
00199 =cut
00200 
00201 sub start {
00202   my ( $self, $value ) = @_;
00203 
00204   if ( defined($value) ) {
00205     $self->{'start'} = $value;
00206   }
00207 
00208   return $self->{'start'};
00209 }
00210 
00211 
00212 
00213 =head2 end
00214 
00215   Arg [1]    : (optional) int $end
00216   Example    : $end = $feat->end();
00217   Description: Getter/Setter for the end of this feature relative to the
00218                start of the slice that it is on.  Note that negative values,
00219                of values exceeding the length of the slice are permitted.  End
00220                must be greater than or equal to start regardless of the strand.
00221                Coordinate values start at 1 and are inclusive.
00222   Returntype : int
00223   Exceptions : none
00224   Caller     : general
00225   Status     : Stable
00226 
00227 =cut
00228 
00229 sub end {
00230   my ( $self, $value ) = @_;
00231 
00232   if ( defined($value) ) {
00233     $self->{'end'} = $value;
00234   }
00235 
00236   return $self->{'end'};
00237 }
00238 
00239 
00240 
00241 
00242 =head2 strand
00243 
00244   Arg [1]    : (optional) int $strand
00245   Example    : $feat->strand(-1);
00246   Description: Getter/Setter for the strand of this feature relative to the
00247                slice it is on.  0 is an unknown or non-applicable strand.  
00248                -1 is the reverse (negative) strand and 1 is the forward 
00249                (positive) strand.  No other values are permitted.
00250   Returntype : int
00251   Exceptions : thrown if an invalid strand argument is passed
00252   Caller     : general
00253   Status     : Stable
00254 
00255 =cut
00256 
00257 sub strand {
00258   my ( $self, $strand ) = @_;
00259 
00260   if ( defined($strand) ) {
00261     if ( $strand != 0 && $strand != 1 && $strand != -1 ) {
00262       throw('strand argument must be 0, -1 or 1');
00263     }
00264 
00265     $self->{'strand'} = $strand;
00266   }
00267 
00268   return $self->{'strand'};
00269 }
00270 
00271 =head2 move
00272 
00273   Arg [1]    : int start
00274   Arg [2]    : int end
00275   Arg [3]    : (optional) int strand
00276   Example    : None
00277   Description: Sets the start, end and strand in one call rather than in 
00278                3 seperate calls to the start(), end() and strand() methods.
00279                This is for convenience and for speed when this needs to be
00280                done within a tight loop.
00281   Returntype : none
00282   Exceptions : Thrown is invalid arguments are provided
00283   Caller     : general
00284   Status     : Stable
00285 
00286 =cut
00287 
00288 sub move {
00289   my $self = shift;
00290 
00291   throw('start and end arguments are required') if(@_ < 2);
00292 
00293   my $start  = shift;
00294   my $end    = shift;
00295   my $strand = shift;
00296 
00297   if(defined($start) && defined($end) && $end < $start) {
00298     throw('start must be less than or equal to end');
00299   }
00300   if(defined($strand) && $strand != 0 && $strand != -1 && $strand != 1) {
00301     throw('strand must be 0, -1 or 1');
00302   }
00303 
00304   $self->{'start'} = $start;
00305   $self->{'end'} = $end;
00306   $self->{'strand'} = $strand if(defined($strand));
00307 }
00308 
00309 
00310 
00311 =head2 length
00312 
00313   Arg [1]    : none
00314   Example    : $length = $feat->length();
00315   Description: Returns the length of this feature
00316   Returntype : Integer
00317   Exceptions : Throws if end < start and the feature is not on a
00318                circular slice
00319   Caller     : general
00320   Status     : Stable
00321 
00322 =cut
00323 
00324 sub length {
00325   my ($self) = @_;
00326 
00327   if ( $self->{'end'} < $self->{'start'} ) {
00328     # if circular, we can work out the length of an origin-spanning
00329     # feature using the size of the underlying region.
00330     if ( $self->slice() && $self->slice()->is_circular() ) {
00331       my $len =
00332         $self->slice()->seq_region_length() -
00333         ( $self->{'start'} - $self->{'end'} ) + 1;
00334       return $len;
00335     } else {
00336       throw(   "Cannot determine length of non-circular feature "
00337              . "where start > end" );
00338     }
00339   }
00340 
00341   return $self->{'end'} - $self->{'start'} + 1;
00342 }
00343 
00344 =head2 analysis
00345 
00346   Arg [1]    : (optional) Bio::EnsEMBL::Analysis $analysis
00347   Example    : $feature->analysis(new Bio::EnsEMBL::Analysis(...))
00348   Description: Getter/Setter for the analysis that is associated with 
00349                this feature.  The analysis describes how this feature 
00350                was derived.
00351   Returntype : Bio::EnsEMBL::Analysis
00352   Exceptions : thrown if an invalid argument is passed
00353   Caller     : general
00354   Status     : Stable
00355 
00356 =cut
00357 
00358 sub analysis {
00359   my $self = shift;
00360 
00361   if(@_) {
00362     my $an = shift;
00363     if(defined($an) && (!ref($an) || !$an->isa('Bio::EnsEMBL::Analysis'))) {
00364       throw('analysis argument must be a Bio::EnsEMBL::Analysis');
00365     }
00366     $self->{'analysis'} = $an;
00367   }
00368 
00369   return $self->{'analysis'};
00370 }
00371 
00372 
00373 
00374 =head2 slice
00375 
00376   Arg [1]    : (optional) Bio::EnsEMBL::Slice $slice
00377   Example    : $seqname = $feature->slice()->name();
00378   Description: Getter/Setter for the Slice that is associated with this 
00379                feature.  The slice represents the underlying sequence that this
00380                feature is on.  Note that this method call is analagous to the
00381                old SeqFeature methods contig(), entire_seq(), attach_seq(),
00382                etc.
00383   Returntype : Bio::EnsEMBL::Slice
00384   Exceptions : thrown if an invalid argument is passed
00385   Caller     : general
00386   Status     : Stable
00387 
00388 =cut
00389 
00390 sub slice {
00391   my ( $self, $slice ) = @_;
00392 
00393   if ( defined($slice) ) {
00394     if (    !check_ref( $slice, 'Bio::EnsEMBL::Slice' )
00395          && !check_ref( $slice, 'Bio::EnsEMBL::LRGSlice' ) )
00396     {
00397       throw('slice argument must be a Bio::EnsEMBL::Slice');
00398     }
00399 
00400     $self->{'slice'} = $slice;
00401   } elsif ( @_ > 1 ) {
00402     delete($self->{'slice'});
00403   }
00404 
00405   return $self->{'slice'};
00406 }
00407 
00408 =head2 equals
00409 
00410   Arg [1]       : Bio::EnsEMBL::Feature object
00411   Example       : if ($featureA->equals($featureB)) { ... }
00412   Description   : Compares two features using various criteria.  The
00413                   test for eqality goes through the following list and
00414                   terminates at the first true match:
00415 
00416                   1. If the two features are the same object, they are
00417                      equal.
00418                   2. If they are of different types (e.g., transcript
00419                      and gene), they are *not* equal.
00420                   3. If they both have dbIDs: if these are the same,
00421                      then they are equal, otherwise not.
00422                   4. If they both have slices and analysis objects:
00423                      if the analysis dbIDs are the same and the
00424                      seq_region_id are the same, along with
00425                      seq_region_start and seq_region_end, then they are
00426                      equal, otherwise not.
00427 
00428                   If none of the above is able to determine equality,
00429                   undef is returned.
00430 
00431     Return type : tri-Boolean (0, 1, undef = "unknown")
00432 
00433     Exceptions  : Thrown if a non-feature is passed as the argument.
00434 
00435 =cut
00436 
00437 sub equals {
00438   my ( $self, $feature ) = @_;
00439 
00440   # If the features are the same object, they are equal.
00441   if ( !defined($feature) ) { return 0 }
00442   if ( $self eq $feature ) { return 1 }
00443 
00444   assert_ref( $feature, 'Bio::EnsEMBL::Feature' );
00445 
00446   # If the features have different types, they are *not* equal.
00447   if ( ref($self) ne ref($feature) ) {
00448     return 0;
00449   }
00450 
00451   # If the features has the same dbID, they are equal.
00452   if ( defined( $self->dbID() ) && defined( $feature->dbID() ) ) {
00453     if   ( $self->dbID() == $feature->dbID() ) { return 1 }
00454     else                                       { return 0 }
00455   }
00456 
00457   # We now know that one of the features do not have a dbID.
00458 
00459   # If the features have the same start, end, strand and seq_region_id,
00460   # and analysis_id, they are equal.
00461   if (
00462      ( defined( $self->analysis() ) && defined( $feature->analysis() ) )
00463      && ( defined( $self->slice() ) && defined( $feature->slice() ) ) )
00464   {
00465     if ( ( $self->start() == $feature->start() ) &&
00466          ( $self->end() == $feature->end() ) &&
00467          ( $self->strand() == $feature->strand() ) &&
00468          ( $self->slice()->get_seq_region_id() ==
00469            $feature->slice()->get_seq_region_id() ) &&
00470          ( $self->analysis()->dbID() == $feature->analysis()->dbID() ) )
00471     {
00472       return 1;
00473     }
00474     else { return 0 }
00475   }
00476 
00477   # We now know that one of the features does not have either analysis
00478   # or slice.
00479 
00480   # We don't know if the features are equal.  This happens if they are
00481   # not the same object but are of the same type, and one of them lacks
00482   # dbID, and if there aren't slice and analysis objects attached to
00483   # them both.
00484   return undef;
00485 } ## end sub equals
00486 
00487 
00488 =head2 transform
00489 
00490   Arg [1]    : string $coord_system
00491                The coord system to transform this feature to.
00492   Arg [2]    : string $version (optional)
00493                The version of the coord system to transform this feature to.
00494   Example    : $feature = $feature->transform('contig');
00495                next if(!defined($feature));
00496   Description: Returns a copy of this feature, but converted to a different
00497                coordinate system. The converted feature will be placed on a
00498                slice which spans an entire sequence region of the new
00499                coordinate system. If the requested coordinate system is the
00500                same coordinate system it is simply placed on a slice which
00501                spans the entire seq_region (as opposed to the original slice
00502                which may have only partially covered the seq_region).
00503 
00504                If a feature spans a boundary in the new coordinate system,
00505                undef is returned instead.
00506 
00507                For example, transforming an exon in contig coordinates to one 
00508                in chromosomal coodinates will place the exon on a slice of an 
00509                entire chromosome.
00510   Returntype : Bio::EnsEMBL::Feature (or undef)
00511   Exceptions : thrown if an invalid coordinate system is provided
00512                warning if Feature is not attached to a slice
00513   Caller     : general, transfer()
00514   Status     : Stable
00515 
00516 =cut
00517 
00518 sub transform {
00519   my $self = shift;
00520   my $cs_name = shift;
00521   my $cs_version = shift;
00522   my $to_slice = shift;
00523 
00524   #
00525   # For backwards compatibility check if the arguments are old style args
00526   #
00527   if(!$cs_name || ref($cs_name)) {
00528     deprecate('Calling transform without a coord system name is deprecated.');
00529     return $self->_deprecated_transform($cs_name);
00530   }
00531 
00532   my $slice = $self->{'slice'};
00533 
00534   if(!$slice) {
00535     warning("Feature cannot be transformed without attached slice.");
00536     return undef;
00537   }
00538 
00539   if(!$slice->adaptor()) {
00540     warning("Feature cannot be transformed without adaptor on" .
00541             " attached slice.");
00542     return undef;
00543   }
00544 
00545   #use db from slice since this feature may not yet be stored in a database
00546   my $db = $slice->adaptor->db();
00547   my $cs = $db->get_CoordSystemAdaptor->fetch_by_name($cs_name, $cs_version);
00548   my $current_cs = $slice->coord_system();
00549 
00550   if(!$current_cs) {
00551     warning("Feature cannot be transformed without CoordSystem on " .
00552             "attached slice.");
00553     return undef;
00554   }
00555 
00556   if(!$cs) {
00557     throw("Cannot transform to unknown coordinate system " .
00558           "[$cs_name $cs_version]\n");
00559   }
00560 
00561   # if feature is already in the requested coordinate system, we can just
00562   # return a copy
00563   if( $cs->equals( $current_cs ) && $slice->start() == 1 &&
00564       $slice->strand() == 1 ) {
00565     my $new_feature;
00566     %$new_feature = %$self;
00567     bless $new_feature, ref $self;
00568     return $new_feature;
00569   }
00570   my $projection;
00571   if(defined($to_slice)){
00572     $projection = $self->project_to_slice( $to_slice );  }
00573   else{
00574     $projection = $self->project( $cs_name, $cs_version );
00575   }
00576 
00577   if(@$projection == 0){
00578     return undef;
00579   }
00580   if( @$projection != 1 and !defined($to_slice)) {
00581 #    warn "MORE than one projection and NO slice specified ";
00582 #    warn "from ".$self->slice->name." to $cs_name, $cs_version\n";
00583     return undef;
00584   }
00585   my $index = 0;
00586   if(defined($to_slice)){
00587     my $found = 0;
00588     my $i = 0;
00589     foreach my $proj (@{$projection}) {
00590       my $slice = $proj->[2];
00591       if($to_slice->get_seq_region_id eq $slice->get_seq_region_id){
00592     $found =1;
00593     $index = $i;
00594       }
00595       $i++;
00596     }
00597     if(!$found){
00598       if(@$projection != 1){
00599     if(@$projection == 0){
00600       warn "number of mappings is ".@$projection."\n";
00601       warn "could not project feature ".ref($self)." from ".$self->slice->seq_region_name." to ".$to_slice->seq_region_name."\n";
00602       warn "In the region of ".$self->slice->start." <-> ".$self->slice->end."\n";
00603       warn "feat start=".($self->slice->start+$self->start)."\tend=".($self->slice->start+$self->end)."\n";
00604     }
00605     else{
00606       foreach my $proj (@{$projection}) {
00607         my $slice = $proj->[2];
00608         warn "available slice ".$slice->seq_regon_name."\n";
00609       }
00610       warn "MORE than one projection and none to slice specified (".$to_slice->seq_region_name.")\n";
00611     }
00612       } 
00613       else {
00614     foreach my $proj (@{$projection}) {
00615       warn "Mapping is to ".$proj->[2]->seq_region_name."\n";
00616     }
00617     warn "One projection but none to slice specified\n";
00618       }
00619       return undef;
00620     }
00621   }
00622  
00623   my $p_slice = $projection->[$index]->[2];
00624   my $slice_adaptor = $db->get_SliceAdaptor;
00625   $slice = $slice_adaptor->fetch_by_region($p_slice->coord_system()->name(),
00626                        $p_slice->seq_region_name(),
00627                        undef, #start
00628                        undef, #end
00629                        1, #strand
00630                        $p_slice->coord_system()->version);
00631   
00632   my $new_feature;
00633   %$new_feature = %$self;
00634   bless $new_feature, ref $self;
00635   $new_feature->{'start'}  = $p_slice->start();
00636   $new_feature->{'end'}    = $p_slice->end();
00637     $new_feature->{'strand'} =
00638       ($self->{'strand'} == 0) ? 0 : $p_slice->strand();
00639   $new_feature->{'slice'}  = $slice;
00640   return $new_feature;
00641 
00642 }
00643 
00644 
00645 
00646 =head2 transfer
00647 
00648   Arg [1]    : Bio::EnsEMBL::Slice $slice
00649                The slice to transfer this feature to
00650   Example    : $feature = $feature->transfer($slice);
00651                next if(!defined($feature));
00652   Description: Returns a copy of this feature which has been shifted onto
00653                another slice.
00654 
00655                If the new slice is in a different coordinate system the
00656                feature is transformed first and then placed on the slice.
00657                If the feature would be split across a coordinate system
00658                boundary or mapped to a gap undef is returned instead.
00659 
00660                If the feature cannot be placed on the provided slice because
00661                it maps to an entirely different location, undef is returned
00662                instead.
00663 
00664   Returntype : Bio::EnsEMBL::Feature (or undef)
00665   Exceptions : throw on incorrect argument
00666                throw if feature does not have attached slice
00667   Caller     : general, transform()
00668   Status     : Stable
00669 
00670 =cut
00671 
00672 
00673 sub transfer {
00674   my $self = shift;
00675   my $slice = shift;
00676 
00677   if(!$slice || !ref($slice) || (!$slice->isa('Bio::EnsEMBL::Slice') && !$slice->isa('Bio::EnsEMBL::LRGSlice'))) {
00678     throw('Slice argument is required');
00679   }
00680 
00681   #make a shallow copy of the feature to be transfered
00682   my $feature;
00683   %{$feature} = %{$self};
00684   bless $feature, ref($self);
00685 
00686   my $current_slice = $self->{'slice'};
00687 
00688   if(!$current_slice) {
00689     warning("Feature cannot be transfered without attached slice.");
00690     return undef;
00691   }
00692 
00693   my $cur_cs = $current_slice->coord_system();
00694   my $dest_cs = $slice->coord_system();
00695 
00696   #if we are not in the same coord system a transformation step is needed first
00697   if(!$dest_cs->equals($cur_cs)) {
00698     $feature = $feature->transform($dest_cs->name, $dest_cs->version, $slice);
00699     return undef if(!defined($feature));
00700     $current_slice = $feature->{'slice'};
00701   }
00702 
00703   # feature went to entirely different seq_region
00704   if($current_slice->seq_region_name() ne $slice->seq_region_name()) {
00705     return undef;
00706   }
00707 
00708   #if the current feature positions are not relative to the start of the
00709   #seq region, convert them so they are
00710   my $cur_slice_start  = $current_slice->start();
00711   my $cur_slice_strand = $current_slice->strand();
00712   if($cur_slice_start != 1 || $cur_slice_strand != 1) {
00713     my $fstart = $feature->{'start'};
00714     my $fend   = $feature->{'end'};
00715 
00716     if($cur_slice_strand == 1) {
00717       $feature->{'start'} = $fstart + $cur_slice_start - 1;
00718       $feature->{'end'}   = $fend   + $cur_slice_start - 1;
00719     } else {
00720       my $cur_slice_end = $current_slice->end();
00721       $feature->{'start'}  = $cur_slice_end - $fend   + 1;
00722       $feature->{'end'}    = $cur_slice_end - $fstart + 1;
00723       $feature->{'strand'} *= -1;
00724     }
00725   }
00726 
00727   my $fstart = $feature->{'start'};
00728   my $fend   = $feature->{'end'};
00729 
00730   #convert to destination slice coords
00731   if($slice->strand == 1) {
00732     $feature->{'start'} = $fstart - $slice->start() + 1;
00733     $feature->{'end'}   = $fend   - $slice->start() + 1;
00734   } else {
00735     $feature->{'start'} = $slice->end() - $fend   + 1;
00736     $feature->{'end'}   = $slice->end() - $fstart + 1;
00737     $feature->{'strand'} *= -1;
00738   }
00739 
00740   $feature->{'slice'} = $slice;
00741 
00742   return $feature;
00743 }
00744 
00745 =head2 project_to_slice
00746 
00747   Arg [1]    : slice to project to
00748 
00749 
00750   Example    :
00751     my $clone_projection = $feature->project_to_slice($slice);
00752 
00753     foreach my $seg (@$clone_projection) {
00754       my $clone = $seg->to_Slice();
00755       print "Features current coords ", $seg->from_start, '-',
00756         $seg->from_end, " project onto clone coords " .
00757         $clone->seq_region_name, ':', $clone->start, '-', $clone->end,
00758         $clone->strand, "\n";
00759     }
00760   Description: Returns the results of 'projecting' this feature onto another
00761                slcie . This is useful to see where a feature
00762                would lie in a coordinate system in which it
00763                crosses a boundary.
00764 
00765                This method returns a reference to a list of
00766                Bio::EnsEMBL::ProjectionSegment objects.
00767                ProjectionSegments are blessed arrays and can also be used as
00768                triplets [from_start,from_end,to_Slice]. The from_start and
00769                from_end are the coordinates relative to the feature start.
00770                For example, if a feature is current 100-200bp on a slice
00771                then the triplets returned might be:
00772                [1,50,$slice1],
00773                [51,101,$slice2]
00774 
00775                The to_Slice is a slice spanning the region on the requested
00776                coordinate system that this feature projected to.
00777 
00778                If the feature projects entirely into a gap then a reference to
00779                an empty list is returned.
00780 
00781   Returntype : list reference of Bio::EnsEMBL::ProjectionSegments
00782                which can also be used as [$start,$end,$slice] triplets
00783   Exceptions : slice does not have an adaptor
00784   Caller     : general
00785   Status     : At Risk
00786 
00787 =cut
00788 
00789 sub project_to_slice {
00790   my $self = shift;
00791   my $to_slice = shift;
00792   my $slice = $self->{'slice'};
00793 
00794   if(!$slice) {
00795     warning("Feature cannot be projected without attached slice.");
00796     return [];
00797   }
00798 
00799 
00800   #get an adaptor from the attached slice because this feature may not yet
00801   #be stored and may not have its own adaptor
00802   my $slice_adaptor = $slice->adaptor();
00803 
00804   if(!$slice_adaptor) {
00805     throw("Cannot project feature because associated slice does not have an " .
00806           " adaptor");
00807   }
00808 
00809   my $strand = $self->strand() * $slice->strand();
00810   #fetch by feature always gives back forward strand slice:
00811   $slice = $slice_adaptor->fetch_by_Feature($self);
00812   $slice = $slice->invert if($strand == -1);
00813   return $slice->project_to_slice($to_slice);
00814 }
00815 
00816 
00817 =head2 project
00818 
00819   Arg [1]    : string $name
00820                The name of the coordinate system to project this feature onto
00821   Arg [2]    : string $version (optional)
00822                The version of the coordinate system (such as 'NCBI34') to
00823                project this feature onto
00824   Example    :
00825     my $clone_projection = $feature->project('clone');
00826 
00827     foreach my $seg (@$clone_projection) {
00828       my $clone = $seg->to_Slice();
00829       print "Features current coords ", $seg->from_start, '-',
00830         $seg->from_end, " project onto clone coords " .
00831         $clone->seq_region_name, ':', $clone->start, '-', $clone->end,
00832         $clone->strand, "\n";
00833     }
00834   Description: Returns the results of 'projecting' this feature onto another
00835                coordinate system.  This is useful to see where a feature
00836                would lie in a coordinate system in which it
00837                crosses a boundary.
00838 
00839                This method returns a reference to a list of
00840                Bio::EnsEMBL::ProjectionSegment objects.
00841                ProjectionSegments are blessed arrays and can also be used as
00842                triplets [from_start,from_end,to_Slice]. The from_start and
00843                from_end are the coordinates relative to the feature start.
00844                For example, if a feature is current 100-200bp on a slice
00845                then the triplets returned might be:
00846                [1,50,$slice1],
00847                [51,101,$slice2]
00848 
00849                The to_Slice is a slice spanning the region on the requested
00850                coordinate system that this feature projected to.
00851 
00852                If the feature projects entirely into a gap then a reference to
00853                an empty list is returned.
00854 
00855   Returntype : list reference of Bio::EnsEMBL::ProjectionSegments
00856                which can also be used as [$start,$end,$slice] triplets
00857   Exceptions : slice does not have an adaptor
00858   Caller     : general
00859   Status     : Stable
00860 
00861 =cut
00862 
00863 sub project {
00864   my $self = shift;
00865   my $cs_name = shift;
00866   my $cs_version = shift;
00867 
00868   my $slice = $self->{'slice'};
00869 
00870   if(!$slice) {
00871     warning("Feature cannot be projected without attached slice.");
00872     return [];
00873   }
00874 
00875 
00876   #get an adaptor from the attached slice because this feature may not yet
00877   #be stored and may not have its own adaptor
00878   my $slice_adaptor = $slice->adaptor();
00879 
00880   if(!$slice_adaptor) {
00881     throw("Cannot project feature because associated slice does not have an " .
00882           " adaptor");
00883   }
00884 
00885   my $strand = $self->strand() * $slice->strand();
00886   #fetch by feature always gives back forward strand slice:
00887   $slice = $slice_adaptor->fetch_by_Feature($self);
00888   $slice = $slice->invert if($strand == -1);
00889   return $slice->project($cs_name, $cs_version);
00890 }
00891 
00892 
00893 
00894 =head2 seqname
00895 
00896   Arg [1]    : (optional) $seqname
00897   Example    : $seqname = $feat->seqname();
00898   Description: Getter/Setter for the name of the sequence that this feature
00899                is on. Normally you can get away with not setting this value
00900                and it will default to the name of the slice on which this
00901                feature is on.  It is useful to set this value on features which
00902                do not ordinarily sit on features such as ProteinFeatures which
00903                sit on peptides.
00904   Returntype : string
00905   Exceptions : none
00906   Caller     : general
00907   Status     : Stable
00908 
00909 =cut
00910 
00911 sub seqname {
00912   my $self = shift;
00913   
00914   if(@_) {
00915     $self->{'seqname'} = shift;
00916   }
00917 
00918   if(!$self->{'seqname'} && $self->slice()) {
00919     return $self->slice->name();
00920   }
00921 
00922   return $self->{'seqname'};
00923 }
00924 
00925 
00926 
00927 
00928 =head2 display_id
00929 
00930   Arg [1]    : none
00931   Example    : print $f->display_id();
00932   Description: This method returns a string that is considered to be
00933                the 'display' identifier.  It is overridden by subclasses to
00934                return an appropriate value for objects of that particular 
00935                class.  If no appropriate display id is available an empty
00936                string is returned instead.
00937   Returntype : string
00938   Exceptions : none
00939   Caller     : web drawing code
00940   Status     : Stable
00941 
00942 =cut
00943 
00944 sub display_id {
00945   my $self = shift;
00946   return '';
00947 }
00948 
00949 
00950 =head2 feature_Slice
00951 
00952   Args       : none
00953   Example    : $slice = $feature->feature_Slice()
00954   Description: This is a convenience method to return a slice that covers the
00955                Area of this feature. The feature start will be at 1 on it, and
00956                it will have the length of this feature.
00957   Returntype : Bio::EnsEMBL::Slice or undef if this feature has no attached
00958                Slice.
00959   Exceptions : warning if Feature does not have attached slice.
00960   Caller     : web drawing code
00961   Status     : Stable
00962 
00963 =cut
00964 
00965 sub feature_Slice {
00966   my $self = shift;
00967 
00968   my $slice = $self->slice();
00969 
00970   if(!$slice) {
00971     warning('Cannot obtain Feature_Slice for feature without attached slice');
00972     return undef;
00973   }
00974 
00975   if($slice->isa("Bio::EnsEMBL::StrainSlice")){
00976     return Bio::EnsEMBL::StrainSlice->new
00977       (-seq_region_name   => $slice->seq_region_name,
00978        -seq_region_length => $slice->seq_region_length,
00979        -coord_system      => $slice->coord_system,
00980        -start             => $self->seq_region_start(),
00981        -end               => $self->seq_region_end(),
00982        -strand            => $self->seq_region_strand(),
00983        -adaptor           => $slice->adaptor(),
00984        -strain_name       => $slice->strain_name());
00985   }
00986   else{
00987     return Bio::EnsEMBL::Slice->new
00988       (-seq_region_name   => $slice->seq_region_name,
00989        -seq_region_length => $slice->seq_region_length,
00990        -coord_system      => $slice->coord_system,
00991        -start             => $self->seq_region_start(),
00992        -end               => $self->seq_region_end(),
00993        -strand            => $self->seq_region_strand(),
00994        -adaptor           => $slice->adaptor());
00995   }
00996 }
00997 
00998 
00999 =head2 seq_region_name
01000 
01001   Arg [1]    : none
01002   Example    : print $feature->seq_region_name();
01003   Description: Gets the name of the seq_region which this feature is on.
01004                Returns undef if this Feature is not on a slice.
01005   Returntype : string or undef
01006   Exceptions : none
01007   Caller     : general
01008   Status     : Stable
01009 
01010 =cut
01011 
01012 sub seq_region_name {
01013   my $self = shift;
01014   my $slice = $self->{'slice'};
01015 
01016   return ($slice) ? $slice->seq_region_name() : undef;
01017 }
01018 
01019 
01020 =head2 seq_region_length
01021 
01022   Arg [1]    : none
01023   Example    : print $feature->seq_region_length();
01024   Description: Returns the length of the seq_region which this feature is on 
01025                Returns undef if this Feature is not on a slice.
01026   Returntype : unsigned int or undef
01027   Exceptions : none
01028   Caller     : general
01029   Status     : Stable
01030 
01031 =cut
01032 
01033 
01034 sub seq_region_length {
01035   my $self = shift;
01036   my $slice = $self->{'slice'};
01037 
01038   return ($slice) ? $slice->seq_region_length() : undef;
01039 }
01040 
01041 
01042 =head2 seq_region_strand
01043 
01044   Arg [1]    : none
01045   Example    : print $feature->seq_region_strand();
01046   Description: Returns the strand of the seq_region which this feature is on 
01047                (i.e. feature_strand * slice_strand)
01048                Returns undef if this Feature is not on a slice.
01049   Returntype : 1,0,-1 or undef
01050   Exceptions : none
01051   Caller     : general
01052   Status     : Stable
01053 
01054 =cut
01055 
01056 
01057 sub seq_region_strand {
01058   my $self = shift;
01059   my $slice = $self->{'slice'};
01060 
01061   return ($slice) ? $slice->strand() * $self->{'strand'} : undef;
01062 }
01063 
01064 
01065 =head2 seq_region_start
01066 
01067   Arg [1]    : none
01068   Example    : print $feature->seq_region_start();
01069   Description: Convenience method which returns the absolute start of this
01070                feature on the seq_region, as opposed to the relative (slice) 
01071                position.
01072 
01073                Returns undef if this feature is not on a slice.
01074   Returntype : int or undef
01075   Exceptions : none
01076   Caller     : general
01077   Status     : Stable
01078 
01079 =cut
01080 
01081 sub seq_region_start {
01082   my ($self) = @_;
01083 
01084   my $slice = $self->slice();
01085 
01086   if ( defined($slice) ) {
01087     my $start;
01088 
01089     if ( $slice->strand() == 1 ) {
01090       if ( defined( $self->start() ) ) {
01091       if ($self->start < 0 && $slice->is_circular) {
01092           $start = $slice->seq_region_length + $self->start;
01093       } else {
01094         $start = $slice->start() + $self->start() - 1;
01095     }
01096       }
01097     } else {
01098       if ( defined( $self->end() ) ) {
01099         $start = $slice->end() - $self->end() + 1;
01100       }
01101     }
01102 
01103     if (    defined($start)
01104          && $slice->is_circular()
01105          && $start > $slice->seq_region_length() )
01106     {
01107       $start -= $slice->seq_region_length();
01108     }
01109 
01110     return $start;
01111   }
01112 
01113   return undef;
01114 } ## end sub seq_region_start
01115 
01116 
01117 =head2 seq_region_end
01118 
01119   Arg [1]    : none
01120   Example    : print $feature->seq_region_end();
01121   Description: Convenience method which returns the absolute end of this
01122                feature on the seq_region, as opposed to the relative (slice)
01123                position.
01124 
01125                Returns undef if this feature is not on a slice.
01126   Returntype : int or undef
01127   Exceptions : none
01128   Caller     : general
01129   Status     : Stable
01130 
01131 =cut
01132 
01133 sub seq_region_end {
01134   my ($self) = @_;
01135 
01136   my $slice = $self->slice();
01137 
01138   if ( defined($slice) ) {
01139     my $end;
01140 
01141     if ( $slice->strand() == 1 ) {
01142       if ( defined( $self->end() ) ) {
01143         $end = $slice->start() + $self->end() - 1;
01144       }
01145     } else {
01146       if ( defined( $self->start() ) ) {
01147         $end = $slice->end() - $self->start() + 1;
01148       }
01149     }
01150 
01151     if (    defined($end)
01152          && $slice->is_circular()
01153          && $end > $slice->seq_region_length() )
01154     {
01155       $end -= $slice->seq_region_length();
01156     }
01157 
01158     return $end;
01159   }
01160 
01161   return undef;
01162 } ## end sub seq_region_end
01163 
01164 
01165 =head2 coord_system_name
01166 
01167   Arg [1]    : none
01168   Example    : print $feature->coord_system_name()
01169   Description: Gets the name of the coord_system which this feature is on.
01170                Returns undef if this Feature is not on a slice.
01171   Returntype : string or undef
01172   Exceptions : none
01173   Caller     : general
01174   Status     : Stable
01175 
01176 =cut
01177 
01178 sub coord_system_name {
01179   my $self = shift;
01180   my $slice = $self->{'slice'};
01181   return ($slice) ? $slice->coord_system_name() : undef;
01182 }
01183 
01184 
01185 =head2 seq
01186 
01187   Args       : none
01188   Example    : my $dna_sequence = $simple_feature->seq();
01189   Description: Returns the dna sequence from the attached slice and 
01190                attached database that overlaps with this feature.
01191                Returns undef if there is no slice or no database.
01192                Returns undef if this feature is unstranded (i.e. strand=0).
01193   Returntype : undef or string
01194   Exceptions : warning if this feature is not stranded
01195   Caller     : general
01196   Status     : Stable
01197 
01198 =cut
01199 
01200 
01201 sub seq {
01202   my $self = shift;
01203 
01204   if( ! defined $self->{'slice'} ) {
01205     return undef;
01206   }
01207 
01208   if(!$self->strand()) {
01209     warning("Cannot retrieve sequence for unstranded feature.");
01210     return undef;
01211   }
01212 
01213   return $self->{'slice'}->subseq($self->start(), $self->end(),
01214                                   $self->strand());
01215 
01216 }
01217 
01218 
01219 
01220 
01221 =head2 get_all_alt_locations
01222 
01223   Arg [1]    : none
01224   Example    : @features = @{$feature->get_all_alt_locations()};
01225                foreach $f (@features) {
01226                  print $f->slice->seq_region_name,' ',$f->start, $f->end,"\n";
01227                }
01228 
01229   Description: Retrieves shallow copies of this feature in its alternate
01230                locations.  A feature can be considered to have multiple
01231                locations when it sits on a alternative structural haplotype
01232                or when it is on a pseudo autosomal region.  Most features will
01233                just return a reference to an empty list though.
01234                The features returned by this method will be on a slice which
01235                covers the entire alternate region.
01236 
01237                Currently this method does not take into account alternate
01238                locations on the alternate locations (e.g. a reference
01239                sequence may have multiple alternate haplotypes.  Asking
01240                for alternate locations of a feature on one of the alternate
01241                haplotypes will give you back the reference location, but not
01242                locations on the other alternate haplotypes).
01243 
01244   Returntype : reference to list of features of the same type of this feature.
01245   Exceptions : none
01246   Caller     : general
01247   Status     : Stable
01248 
01249 =cut
01250 
01251 sub get_all_alt_locations {
01252   my $self = shift;
01253   my $return_all = shift || 0;
01254 
01255   my $slice = $self->{'slice'} or return [];
01256   my $sa = $slice->adaptor() or return [];
01257 
01258   # get slice of entire region
01259   $slice = $sa->fetch_by_seq_region_id($slice->get_seq_region_id);
01260 
01261   my $axfa = $sa->db->get_AssemblyExceptionFeatureAdaptor();
01262   my $axfs = $axfa->fetch_all_by_Slice($slice);
01263 
01264   my (@haps, @alt);
01265 
01266   foreach my $axf (@$axfs) {
01267     if(uc($axf->type()) eq 'HAP') {
01268       push @haps, $axf;
01269     } elsif(uc($axf->type()) =~ 'PAR') {
01270       push @alt, $axf;
01271     } elsif( $axf->type() eq "PATCH_FIX"){
01272       push @haps, $axf;
01273     } elsif( $axf->type() eq "PATCH_FIX REF"){
01274       push @haps, $axf  if $return_all > 0 ;
01275     } elsif( $axf->type() eq "HAP REF" ) {
01276       push @haps, $axf if $return_all > 0 ;
01277       # do nothing when you are on REF
01278     } elsif( $axf->type() eq "PATCH_NOVEL"){
01279       push @haps, $axf;
01280     }elsif( $axf->type() eq "PATCH_NOVEL REF"){
01281       push @haps, $axf  if $return_all > 0 ;
01282     } else {
01283       warning("Unknown exception feature type ". $axf->type()."- ignoring.");
01284     }
01285   }
01286 
01287   # regions surrounding hap are those of interest, not hap itself
01288   # convert hap alt. exc. features to regions around haps instead
01289   foreach my $h (@haps) {
01290     my $haslice = $h->alternate_slice();
01291     my $hacs    = $haslice->coord_system();
01292 
01293     if($h->start() > 1 && $haslice->start() > 1) {
01294       my $aslice = $sa->fetch_by_region($hacs->name(),
01295                                         $haslice->seq_region_name(),
01296                                         1,
01297                                         $haslice->start()-1,
01298                                         $haslice->strand(),
01299                                         $hacs->version());
01300 
01301       push @alt, Bio::EnsEMBL::AssemblyExceptionFeature->new
01302         (-start  => 1,
01303          -end    => $h->start()-1,
01304          -alternate_slice => $aslice);
01305     }
01306 
01307     if($h->end() < $slice->seq_region_length() &&
01308        $haslice->end < $haslice->seq_region_length()) {
01309       my $aslice = $sa->fetch_by_region($hacs->name(),
01310                                         $haslice->seq_region_name(),
01311                                         $haslice->end()+1,
01312                                         $haslice->seq_region_length(),
01313                                         $haslice->strand(),
01314                                         $hacs->version());
01315 
01316       push @alt, Bio::EnsEMBL::AssemblyExceptionFeature->new
01317         (-start  => $h->end() + 1,
01318          -end    => $slice->seq_region_length(),
01319          -alternate_slice => $aslice);
01320     }
01321   }
01322 
01323 
01324   # check if exception regions contain our feature
01325 
01326   my @features;
01327 
01328   foreach my $axf (@alt) {
01329     # ignore other region if feature is not entirely on it
01330     next if($self->seq_region_start() < $axf->start() ||
01331             $self->seq_region_end()   > $axf->end());
01332 
01333     # quick shallow copy of the feature
01334     my $f;
01335     %$f = %$self;
01336     bless $f, ref($self);
01337 
01338     my $aslice = $axf->alternate_slice();
01339 
01340     # position feature on entire slice of other region
01341     $f->{'start'}  = $f->seq_region_start() - $axf->start() + $aslice->start();
01342     $f->{'end'}    = $f->seq_region_end()   - $axf->start() + $aslice->start();
01343     $f->{'strand'} *= $aslice->strand();
01344 
01345     $f->{'slice'} = $sa->fetch_by_seq_region_id($aslice->get_seq_region_id());
01346 
01347     push @features, $f;
01348   }
01349 
01350   return \@features;
01351 }
01352 
01353 
01354 =head2 overlaps
01355 
01356   Arg [1]    : Bio::EnsEMBL::Feature $f
01357                The other feature you want to check overlap with this feature
01358                for.
01359   Description: This method does a range comparison of this features start and
01360                end and compares it with another features start and end. It will
01361                return true if these ranges overlap and the features are on the
01362                same seq_region.
01363   Returntype : TRUE if features overlap, FALSE if they don't
01364   Exceptions : warning if features are on different seq_regions
01365   Caller     : general
01366   Status     : Stable
01367 
01368 =cut
01369 
01370 sub overlaps {
01371   my $self = shift;
01372   my $f = shift;
01373 
01374   my $sr1_name = $self->seq_region_name;
01375   my $sr2_name = $f->seq_region_name;
01376 
01377   if ($sr1_name and $sr2_name and ($sr1_name ne $sr2_name)) {
01378     warning("Bio::EnsEMBL::Feature->overlaps(): features are on different seq regions.");
01379     return undef;
01380   }
01381   
01382   return ($self->seq_region_end >= $f->seq_region_start and $self->seq_region_start <= $f->seq_region_end);
01383 }
01384 
01385 
01386 =head2 get_overlapping_Genes
01387 
01388   Description: Get all the genes that overlap this feature.
01389   Returntype : list ref of Bio::EnsEMBL::Gene
01390   Caller     : general
01391   Status     : UnStable
01392 
01393 =cut
01394 
01395 sub get_overlapping_Genes{
01396   my $self = shift;
01397 
01398   my $slice = $self->feature_Slice;
01399   return $slice->get_all_Genes();
01400 }
01401 
01402 # query for absolute nearest.
01403 # select x.display_label, g.gene_id, g.seq_region_start, ABS(cast((32921638 - g.seq_region_end) as signed))  as 'dist' from gene g, xref x where g.display_xref_id = x.xref_id and seq_region_id = 27513 order by ABS(cast((32921638 - g.seq_region_end) as signed)) limit 10;
01404 
01405 =head2 get_nearest_Gene
01406 
01407   Description: Get all the nearest  gene to the feature
01408   Returntype : Bio::EnsEMBL::Gene
01409   Caller     : general
01410   Status     : UnStable
01411 
01412 =cut
01413 
01414 sub get_nearest_Gene {
01415   my $self = shift;
01416   my $stranded = shift;
01417   my $stream = shift;
01418 
01419   my $ga = Bio::EnsEMBL::Registry->get_adaptor($self->adaptor->db->species,"core","Gene");
01420 
01421   return $ga->fetch_nearest_Gene_by_Feature($self, $stranded, $stream);
01422 
01423 }
01424 
01425 =head2 summary_as_hash
01426 
01427   Example       : $feature_summary = $feature->summary_as_hash();
01428   Description   : Retrieves a textual summary of this Feature.
01429                   Should be overidden by subclasses for specific tweaking
01430   Returns       : hashref of arrays of descriptive strings
01431   Status        : Intended for internal use
01432 =cut
01433 
01434 sub summary_as_hash {
01435   my $self = shift;
01436   my %summary;
01437   $summary{'ID'} = $self->display_id;
01438   $summary{'start'} = $self->seq_region_start;
01439   $summary{'end'} = $self->seq_region_end;
01440   $summary{'strand'} = $self->strand;
01441   $summary{'seq_region_name'} = $self->seq_region_name;
01442   return \%summary;
01443 }
01444 
01445 =head2 species
01446 
01447   Example           : $feature->species();
01448   Description   : Shortcut to the feature's DBAdaptor and returns its species name 
01449   Returntype    : String the species name
01450   Exceptions    : Thrown if there is no attached adaptor
01451   Caller      : Webcode
01452 
01453 =cut
01454 
01455 sub species {
01456   my ($self) = @_;
01457   throw "Can only call this method if you have attached an adaptor" if ! $self->adaptor();
01458   reutrn $self->adaptor()->db()->species();
01459 }
01460 
01461 
01462 ##############################################
01463 # Methods included for backwards compatibility
01464 ##############################################
01465 
01466 
01467 # contig
01468 #
01469 # This method is included for backwards compatibility.
01470 # Use slice() instead
01471 #
01472 sub contig {
01473   deprecate('Use slice() instead');
01474   slice(@_);
01475 }
01476 
01477 
01478 
01479 # sub_SeqFeature
01480 #
01481 # This method is only for genebuild backwards compatibility.
01482 # Avoid using it if possible
01483 #
01484 sub sub_SeqFeature{
01485   my ($self) = @_;
01486   return @{$self->{'_gsf_sub_array'}} if($self->{'_gsf_sub_array'});
01487 }
01488 
01489 # add_sub_SeqFeature
01490 #
01491 # This method is only for genebuild backwards compatibility.
01492 # Avoid using it if possible
01493 #
01494 sub add_sub_SeqFeature{
01495   my ($self,$feat,$expand) = @_;
01496   my ($p, $f, $l) = caller;
01497   if( $expand eq 'EXPAND' ) {
01498     # if this doesn't have start/end set - forget it!
01499     if( ! $self->start && ! $self->end ) {
01500       
01501       $self->start($feat->start());
01502       $self->end($feat->end());
01503       $self->strand($feat->strand);
01504     } else {
01505       if( $feat->start < $self->start ) {
01506         $self->start($feat->start);
01507       }
01508 
01509       if( $feat->end > $self->end ) {
01510         $self->end($feat->end);
01511       }
01512     }
01513    } else {
01514      if($self->start > $feat->start || $self->end < $feat->end) {
01515        throw("$feat is not contained within parent feature, " .
01516              "and expansion is not valid");
01517      }
01518    }
01519 
01520    push(@{$self->{'_gsf_sub_array'}},$feat);
01521 }
01522 
01523 # flush_sub_SeqFeature
01524 #
01525 # This method is only for genebuild backwards compatibility.
01526 # Avoid using it isf possible
01527 #
01528 sub flush_sub_SeqFeature {
01529   my ($self) = @_;
01530   $self->{'_gsf_sub_array'} = [];
01531 }
01532 
01533 
01534 sub _deprecated_transform {
01535   my $self = shift;
01536   my $arg = shift;
01537 
01538   if(!$arg) {
01539     warning("Calling transform() with no arguments is deprecated.\n".
01540           "A coordinate system name argument should be used instead.\n".
01541           "You probably wanted transform('seqlevel') or transform('contig').");
01542     return $self->transform('seqlevel');
01543   }
01544 
01545   if(ref($arg) eq 'Bio::EnsEMBL::Slice') {
01546     if($arg->{'empty'}) {
01547       warning("Calling transform with an empty slice is deprecated.\n" .
01548                 "A coordinate system name argument should be used instead.\n".
01549                 "You probably wanted transform('chromosome') or " .
01550                 "transform('toplevel')");
01551       return $self->transform('toplevel');
01552     }
01553     warning("Calling transform with a slice is deprecated.\n" .
01554               "Use the transfer method instead");
01555     return $self->transfer($arg);
01556   }
01557 
01558   warning("Calling transform with a [".ref($arg)."] arg is no longer " .
01559           "(or never was) supported.  Doing nothing instead.");
01560 
01561   return $self;
01562 }
01563 
01564 # id
01565 #
01566 # This method is included for backwards compatibility only.
01567 # Use hseqname or dbID or stable_id instead
01568 #
01569 sub id {
01570   my $self = shift;
01571   deprecate("id method is not used - use display_id instead");
01572   return $self->{'stable_id'} if($self->{'stable_id'});
01573   return $self->{'hseqname'} if($self->{'hseqname'});
01574   return $self->{'seqname'}  if($self->{'seqname'});
01575   return $self->{'dbID'};
01576 }
01577 
01578 1;