BioPerl

 view release on metacpan or  search on metacpan

Bio/Map/PositionI.pm  view on Meta::CPAN



=head2 less_than

 Title   : less_than
 Usage   : if ($position->less_than($other_position)) {...}
 Function: Ask if this Position ends before another starts.
 Returns : boolean
 Args    : arg #1 = a Bio::RangeI (eg. a Bio::Map::Position) to compare this
                    one to (mandatory)
           arg #2 = optional Bio::Map::RelativeI to ask if the Position is less
                    in terms of their relative position to the thing described
                    by that Relative

=cut

sub less_than {
    my ($self, $other, $rel) = @_;
    
    my ($own_start, $own_end) = $self->_pre_rangei($self, $rel);
    my ($other_start, $other_end) = $self->_pre_rangei($other, $rel);
    
    return $own_end < $other_start;
}

=head2 greater_than

 Title   : greater_than
 Usage   : if ($position->greater_than($other_position)) {...}
 Function: Ask if this Position starts after another ends.
 Returns : boolean
 Args    : arg #1 = a Bio::RangeI (eg. a Bio::Map::Position) to compare this
                    one to (mandatory)
           arg #2 = optional Bio::Map::RelativeI to ask if the Position is
                    greater in terms of their relative position to the thing
                    described by that Relative

=cut

sub greater_than {
    my ($self, $other, $rel) = @_;
    
    my ($own_start, $own_end) = $self->_pre_rangei($self, $rel);
    my ($other_start, $other_end) = $self->_pre_rangei($other, $rel);
    
    return $own_start > $other_end;
}

=head2 overlaps

  Title   : overlaps
  Usage   : if ($p1->overlaps($p2)) {...}
  Function: Tests if $p1 overlaps $p2.
  Returns : True if the positions overlap (regardless of map), false otherwise
  Args    : arg #1 = a Bio::RangeI (eg. a Bio::Map::Position) to compare this
                     one to (mandatory)
            arg #2 = optional strand-testing arg ('strong', 'weak', 'ignore')
            arg #3 = optional Bio::Map::RelativeI to ask if the Positions
                     overlap in terms of their relative position to the thing
                     described by that Relative
            arg #4 = optional minimum percentage length of the overlap before
                     reporting an overlap exists (default 0)

=cut

sub overlaps {
    # overriding the RangeI implementation so we can handle Relative
    my ($self, $other, $so, $rel, $min_percent) = @_;
    $min_percent ||= 0;
    
    my ($own_min, $other_min) = (0, 0);
    if ($min_percent > 0) {
        $own_min = (($self->length / 100) * $min_percent) - 1;
        $other_min = (($other->length / 100) * $min_percent) - 1;
    }
    
    my ($own_start, $own_end) = $self->_pre_rangei($self, $rel);
    my ($other_start, $other_end) = $self->_pre_rangei($other, $rel);
    
    return ($self->_testStrand($other, $so) and not
            (($own_start + $own_min > $other_end or $own_end - $own_min < $other_start) ||
             ($own_start > $other_end - $other_min or $own_end < $other_start + $other_min)));
}

=head2 contains

  Title   : contains
  Usage   : if ($p1->contains($p2)) {...}
  Function: Tests whether $p1 totally contains $p2.
  Returns : true if the argument is totally contained within this position
            (regardless of map), false otherwise
  Args    : arg #1 = a Bio::RangeI (eg. a Bio::Map::Position) to compare this
                     one to, or scalar number (mandatory)
            arg #2 = optional strand-testing arg ('strong', 'weak', 'ignore')
            arg #3 = optional Bio::Map::RelativeI to ask if the Position
                     is contained in terms of their relative position to the
                     thing described by that Relative

=cut

sub contains {
    # overriding the RangeI implementation so we can handle Relative
    my ($self, $other, $so, $rel) = @_;
    
    my ($own_start, $own_end) = $self->_pre_rangei($self, $rel);
    my ($other_start, $other_end) = $self->_pre_rangei($other, $rel);
    
    return ($self->_testStrand($other, $so) and
			$other_start >= $own_start and $other_end <= $own_end);
}

=head2 intersection

 Title   : intersection
 Usage   : ($start, $stop, $strand) = $p1->intersection($p2)
           ($start, $stop, $strand) = Bio::Map::Position->intersection(\@positions);
           $mappable = $p1->intersection($p2, undef, $relative);
           $mappable = Bio::Map::Position->intersection(\@positions);
 Function: gives the range that is contained by all ranges
 Returns : undef if they do not overlap, OR
           Bio::Map::Mappable object who's positions are the
           cross-map-calculated intersection of the input positions on all the
           maps that the input positions belong to, OR, in list context, a three
           element array (start, end, strand)
 Args    : arg #1 = [REQUIRED] a Bio::RangeI (eg. a Bio::Map::Position) to
                    compare this one to, or an array ref of Bio::RangeI
           arg #2 = optional strand-testing arg ('strong', 'weak', 'ignore')
           arg #3 = optional Bio::Map::RelativeI to ask how the Positions
                    intersect in terms of their relative position to the thing
                    described by that Relative

=cut

sub intersection {

Bio/Map/PositionI.pm  view on Meta::CPAN

        
        push(@starts, $start);
        push(@ends, $end);
    }
    
	@starts = sort { $a <=> $b } @starts;
	@ends   = sort { $a <=> $b } @ends;
	my $start = shift @starts;
	my $end = pop @ends;
    
    my @unions;
    foreach my $known_map (values %known_maps) {
        my $new_union = $self->new(-start => $start,
                                   -end => $end,
                                   -strand => $union_strand,
                                   -map => $known_map);
        $new_union->relative($rel) if $rel;
        push(@unions, $new_union);
    }
    unless (@unions) {
        @unions = ($self->new(-start => $start,
                         -end => $end,
                         -strand => $union_strand));
        $unions[0]->relative($rel) if $rel;
    }
    
    my $result = Bio::Map::Mappable->new();
    $result->add_position(@unions); # sneaky, add_position can take a list of positions
    return $result;
}

=head2 overlap_extent

 Title   : overlap_extent
 Usage   : ($a_unique,$common,$b_unique) = $a->overlap_extent($b)
 Function: Provides actual amount of overlap between two different
           positions
 Example :
 Returns : array of values containing the length unique to the calling 
           position, the length common to both, and the length unique to 
           the argument position
 Args    : a position

=cut

#*** should this be overridden from RangeI?

=head2 disconnected_ranges

 Title   : disconnected_ranges
 Usage   : my @disc_ranges = Bio::Map::Position->disconnected_ranges(@ranges);
 Function: Creates the minimal set of positions such that each input position is
           fully contained by at least one output position, and none of the
           output positions overlap.
 Returns : Bio::Map::Mappable with the calculated disconnected ranges
 Args    : a Bio::Map::PositionI to compare this one to, or a list of such,
           OR
           a single Bio::Map::PositionI or array ref of such AND a
           Bio::Map::RelativeI to consider all Position's co-ordinates in terms
           of their relative position to the thing described by that Relative,
           AND, optionally, an int for the minimum percentage of overlap that
           must be present before considering two ranges to be overlapping
           (default 0)

=cut

sub disconnected_ranges {
    # overriding the RangeI implementation so we can transfer map and handle
    # Relative
    my ($self, @args) = @_;
    $self->throw("Not enough arguments") unless @args >= 1;
    
    my @positions;
    my $rel;
    my $overlap = 0;
    if ($self eq "Bio::Map::PositionI") {
		$self = "Bio::Map::Position";
		$self->warn("calling static methods of an interface is deprecated; use $self instead");
	}
	if (ref $self) {
		push(@positions, $self);
	}
    if (ref $args[0] eq 'ARRAY') {
        push(@positions, @{shift(@args)});
    }
    else {
        push(@positions, shift(@args));
    }
    if ($args[0] && $args[0]->isa('Bio::Map::RelativeI')) {
        $rel = shift(@args);
        $overlap = shift(@args);
    }
    foreach my $arg (@args) {
        push(@positions, $arg) if $arg;
    }
    $self->throw("Need at least 2 Positions") unless @positions >= 2;
    
    my %known_maps;
    foreach my $pos (@positions) {
        $pos->isa('Bio::Map::PositionI') || $self->throw("Must supply only Bio::Map::PositionI objects, not [$pos]");
        my $map = $pos->map || next;
        $known_maps{$map->unique_id} = $map;
    }
    my %prior_positions;
    foreach my $map (values %known_maps) {
        foreach my $pos ($map->get_positions) {
            $prior_positions{$pos} = 1;
        }
    }
    
    my @outranges = ();
    foreach my $inrange (@positions) {
        my @outranges_new = ();
        my %overlapping_ranges = ();
        
        for (my $i=0; $i<@outranges; $i++) {
            my $outrange = $outranges[$i];
            if ($inrange->overlaps($outrange, undef, $rel, $overlap)) {
                my $union_able = $inrange->union($outrange, $rel); # using $inrange->union($outrange, $rel); gives >6x speedup,
                                                                   # but different answer, not necessarily incorrect...
                foreach my $pos ($union_able->get_positions) {



( run in 2.373 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )