Bio-EnsEMBL

 view release on metacpan or  search on metacpan

lib/Bio/EnsEMBL/Feature.pm  view on Meta::CPAN


=cut

=head1 NAME

Bio::EnsEMBL::Feature - Ensembl specific sequence feature.

=head1 SYNOPSIS

    my $feat = new Bio::EnsEMBL::Feature(
      -start  => 100,
      -end    => 220,
      -strand => -1,
      -slice  => $slice,
      -analysis => $analysis
    );

    my $start  = $feat->start();
    my $end    = $feat->end();
    my $strand = $feat->strand();

    # Move the feature to the chromosomal coordinate system
    $feature = $feature->transform('chromosome');

    # Move the feature to a different slice (possibly on another coord
    # system)
    $feature = $feature->transfer($new_slice);

    # Project the feature onto another coordinate system possibly across
    # boundaries:
    @projection = @{ $feature->project('contig') };

    # Change the start, end, and strand of the feature in place
    $feature->move( $new_start, $new_end, $new_strand );

=head1 DESCRIPTION

This is the Base feature class from which all Ensembl features inherit.
It provides a bare minimum functionality that all features require.  It
basically describes a location on a sequence in an arbitrary coordinate
system.

=head1 METHODS

=cut


package Bio::EnsEMBL::Feature;
$Bio::EnsEMBL::Feature::VERSION = '114.0.0';
use strict;
use warnings;

use Bio::EnsEMBL::Storable;
use Bio::EnsEMBL::Utils::Argument qw(rearrange);
use Bio::EnsEMBL::Utils::Exception qw(throw warning);
use Bio::EnsEMBL::Utils::Scalar qw(check_ref assert_ref);
use Bio::EnsEMBL::Slice;

use vars qw(@ISA);

use Scalar::Util qw(weaken);

@ISA = qw(Bio::EnsEMBL::Storable);


=head2 new

  Arg [-SLICE]: Bio::EnsEMBL::SLice - Represents the sequence that this
                feature is on. The coordinates of the created feature are
                relative to the start of the slice.
  Arg [-START]: The start coordinate of this feature relative to the start
                of the slice it is sitting on.  Coordinates start at 1 and
                are inclusive.
  Arg [-END]  : The end coordinate of this feature relative to the start of
                the slice it is sitting on.  Coordinates start at 1 and are
                inclusive.
  Arg [-STRAND]: The orientation of this feature.  Valid values are 1,-1,0.
  Arg [-SEQNAME] : A seqname to be used instead of the default name of the 
                of the slice.  Useful for features that do not have an 
                attached slice such as protein features.
  Arg [-dbID]   : (optional) internal database id
  Arg [-ADAPTOR]: (optional) Bio::EnsEMBL::DBSQL::BaseAdaptor
  Example    : $feature = Bio::EnsEMBL::Feature->new(-start    => 1, 
                                                     -end      => 100,
                                                     -strand   => 1,
                                                     -slice    => $slice,
                                                     -analysis => $analysis);
  Description: Constructs a new Bio::EnsEMBL::Feature.  Generally subclasses
               of this method are instantiated, rather than this class itself.
  Returntype : Bio::EnsEMBL::Feature
  Exceptions : Thrown on invalid -SLICE, -ANALYSIS, -STRAND ,-ADAPTOR arguments
  Caller     : general, subclass constructors
  Status     : Stable

=cut


sub new {
  my $caller = shift;

  my $class = ref($caller) || $caller;
  my ( $start, $end, $strand, $slice, $analysis,$seqname, $dbID, $adaptor ) =
      rearrange(['START','END','STRAND','SLICE','ANALYSIS', 'SEQNAME',
		 'DBID', 'ADAPTOR'], @_);   
  if($slice) {
    if(!ref($slice) || !($slice->isa('Bio::EnsEMBL::Slice') or $slice->isa('Bio::EnsEMBL::LRGSlice')) ) {
      throw('-SLICE argument must be a Bio::EnsEMBL::Slice not '.$slice);
    }
  }

  if($analysis) {
    if(!ref($analysis) || !$analysis->isa('Bio::EnsEMBL::Analysis')) {
      throw('-ANALYSIS argument must be a Bio::EnsEMBL::Analysis not '.
            $analysis);
    }
  }

  if(defined($strand)) {
    if(!($strand == 1) && !($strand == -1) && !($strand == 0)) {
      throw('-STRAND argument must be 1, -1, or 0');
    }

lib/Bio/EnsEMBL/Feature.pm  view on Meta::CPAN

  $slice = $slice_adaptor->fetch_by_region($p_slice->coord_system()->name(),
					   $p_slice->seq_region_name(),
					   undef, #start
					   undef, #end
					   1, #strand
					   $p_slice->coord_system()->version);
  
  my $new_feature;
  %$new_feature = %$self;
  bless $new_feature, ref $self;
  $new_feature->{'start'}  = $p_slice->start();
  $new_feature->{'end'}    = $p_slice->end();
    $new_feature->{'strand'} =
      ($self->{'strand'} == 0) ? 0 : $p_slice->strand();
  $new_feature->{'slice'}  = $slice;
  return $new_feature;

}



=head2 transfer

  Arg [1]    : Bio::EnsEMBL::Slice $slice
               The slice to transfer this feature to
  Example    : $feature = $feature->transfer($slice);
               next if(!defined($feature));
  Description: Returns a copy of this feature which has been shifted onto
               another slice.

               If the new slice is in a different coordinate system the
               feature is transformed first and then placed on the slice.
               If the feature would be split across a coordinate system
               boundary or mapped to a gap undef is returned instead.

               If the feature cannot be placed on the provided slice because
               it maps to an entirely different location, undef is returned
               instead.

  Returntype : Bio::EnsEMBL::Feature (or undef)
  Exceptions : throw on incorrect argument
               throw if feature does not have attached slice
  Caller     : general, transform()
  Status     : Stable

=cut


sub transfer {
  my $self = shift;
  my $slice = shift;

  if(!$slice || !ref($slice) || (!$slice->isa('Bio::EnsEMBL::Slice') && !$slice->isa('Bio::EnsEMBL::LRGSlice'))) {
    throw('Slice argument is required');
  }

  #make a shallow copy of the feature to be transfered
  my $feature;
  %{$feature} = %{$self};
  bless $feature, ref($self);
  weaken $feature->{adaptor};

  my $current_slice = $self->{'slice'};

  if(!$current_slice) {
    warning("Feature cannot be transfered without attached slice.");
    return undef;
  }

  my $cur_cs = $current_slice->coord_system();
  my $dest_cs = $slice->coord_system();

  #if we are not in the same coord system a transformation step is needed first
  if(!$dest_cs->equals($cur_cs)) {
    $feature = $feature->transform($dest_cs->name, $dest_cs->version, $slice);
    return undef if(!defined($feature));
    $current_slice = $feature->{'slice'};
  }

  # feature went to entirely different seq_region
  if($current_slice->seq_region_name() ne $slice->seq_region_name()) {
    return undef;
  }

  #if the current feature positions are not relative to the start of the
  #seq region, convert them so they are
  my $cur_slice_start  = $current_slice->start();
  my $cur_slice_strand = $current_slice->strand();
  if($cur_slice_start != 1 || $cur_slice_strand != 1) {
    my $fstart = $feature->{'start'};
    my $fend   = $feature->{'end'};

    if($cur_slice_strand == 1) {
      $feature->{'start'} = $fstart + $cur_slice_start - 1;
      $feature->{'end'}   = $fend   + $cur_slice_start - 1;
    } else {
      my $cur_slice_end = $current_slice->end();
      $feature->{'start'}  = $cur_slice_end - $fend   + 1;
      $feature->{'end'}    = $cur_slice_end - $fstart + 1;
      $feature->{'strand'} *= -1;
    }
  }

  my $fstart = $feature->{'start'};
  my $fend   = $feature->{'end'};

  #convert to destination slice coords
  if($slice->strand == 1) {
    $feature->{'start'} = $fstart - $slice->start() + 1;
    $feature->{'end'}   = $fend   - $slice->start() + 1;
  } else {
    $feature->{'start'} = $slice->end() - $fend   + 1;
    $feature->{'end'}   = $slice->end() - $fstart + 1;
    $feature->{'strand'} *= -1;
  }

  $feature->{'slice'} = $slice;

  return $feature;
}



( run in 0.958 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )