BioPerl
view release on metacpan or search on metacpan
Bio/DB/GFF/Feature.pm view on Meta::CPAN
# error message of last resort
$self->throw(qq(Can't locate object method "$func_name" via package "$pack"));
}#'
=head2 adjust_bounds
Title : adjust_bounds
Usage : $feature->adjust_bounds
Function: adjust the bounds of a feature
Returns : ($start,$stop,$strand)
Args : none
Status : Public
This method adjusts the boundaries of the feature to enclose all its
subfeatures. It returns the new start, stop and strand of the
enclosing feature.
=cut
# adjust a feature so that its boundaries are synched with its subparts' boundaries.
# this works recursively, so subfeatures can contain other features
sub adjust_bounds {
my $self = shift;
my $shrink = shift;
my $g = $self->{group};
my $first = 0;
my $tfirst = 0;
if (my $subfeat = $self->{subfeatures}) {
for my $list (values %$subfeat) {
for my $feat (@$list) {
# fix up our bounds to hold largest subfeature
my($start,$stop,$strand) = $feat->adjust_bounds($shrink);
if (defined($self->{fstrand})) {
$self->debug("Subfeature's strand ($strand) doesn't match parent strand ($self->{fstrand})\n") if $self->{fstrand} ne $strand;
} else {
$self->{fstrand} = $strand;
}
my ($low,$high) = $start < $stop ? ($start,$stop) : ($stop,$start);
if ($shrink && !$first++) {
# first subfeature resets start & stop:
$self->{start} = $self->{fstrand} ne '-' ? $low : $high;
$self->{stop} = $self->{fstrand} ne '-' ? $high : $low;
} else {
if ($self->{fstrand} ne '-') {
$self->{start} = $low
if (!defined($self->{start})) || $low < $self->{start};
$self->{stop} = $high
if (!defined($self->{stop})) || $high > $self->{stop};
} else {
$self->{start} = $high
if (!defined($self->{start})) || $high > $self->{start};
$self->{stop} = $low
if (!defined($self->{stop})) || $low < $self->{stop};
}
}
# fix up endpoints of targets too (for homologies only)
my $h = $feat->group;
next unless $h && $h->isa('Bio::DB::GFF::Homol');
next unless $g && $g->isa('Bio::DB::GFF::Homol');
($start,$stop) = ($h->{start},$h->{stop});
if ($shrink && !$tfirst++) {
$g->{start} = $start;
$g->{stop} = $stop;
} else {
if ($start <= $stop) {
$g->{start} = $start if (!defined($g->{start})) || $start < $g->{start};
$g->{stop} = $stop if (!defined($g->{stop})) || $stop > $g->{stop};
} else {
$g->{start} = $start if (!defined($g->{start})) || $start > $g->{start};
$g->{stop} = $stop if (!defined($g->{stop})) || $stop < $g->{stop};
}
}
}
}
}
($self->{start},$self->{stop},$self->strand);
}
=head2 sort_features
Title : sort_features
Usage : $feature->sort_features
Function: sort features
Returns : nothing
Args : none
Status : Public
This method sorts subfeatures in ascending order by their start
position. For reverse strand features, it sorts subfeatures in
descending order. After this is called sub_SeqFeature will return the
features in order.
This method is called internally by merged_segments().
=cut
# sort features
sub sort_features {
my $self = shift;
return if $self->{sorted}++;
my $strand = $self->strand or return;
my $subfeat = $self->{subfeatures} or return;
for my $type (keys %$subfeat) {
$subfeat->{$type} = [map { $_->[0] }
sort {$a->[1] <=> $b->[1] }
map { [$_,$_->start] }
@{$subfeat->{$type}}] if $strand > 0;
$subfeat->{$type} = [map { $_->[0] }
sort {$b->[1] <=> $a->[1]}
map { [$_,$_->start] }
@{$subfeat->{$type}}] if $strand < 0;
}
}
=head2 asString
Title : asString
Usage : $string = $feature->asString
Function: return human-readabled representation of feature
Returns : a string
Args : none
Status : Public
This method returns a human-readable representation of the feature and
is called by the overloaded "" operator.
=cut
sub asString {
my $self = shift;
my $type = $self->type;
my $name = $self->group;
return "$type($name)" if $name;
return $type;
# my $type = $self->method;
# my $id = $self->group || 'unidentified';
# return join '/',$id,$type,$self->SUPER::asString;
}
sub name {
my $self =shift;
return $self->group || $self->SUPER::name;
}
=head2 gff_string
Title : gff_string
Usage : $string = $feature->gff_string
Function: return GFF2 of GFF2.5 representation of feature
Returns : a string
Args : none
Status : Public
=cut
sub gff_string {
my $self = shift;
my $version = $self->version;
# gff3_string and gff_string are synonymous if the version is set to 3
return $self->gff3_string(@_) if $version == 3;
my ($start,$stop) = ($self->start,$self->stop);
# the defined() tests prevent uninitialized variable warnings, when dealing with clone objects
# whose endpoints may be undefined
($start,$stop) = ($stop,$start) if defined($start) && defined($stop) && $start > $stop;
my ($class,$name) = ('','');
my $strand = ('-','.','+')[$self->strand+1];
my @group;
if (my $t = $self->target) {
push @group, $version == 2.5 ? $self->flatten_target($t,2.5)
: $self->flatten_target($t);
}
elsif (my $g = $self->group) {
$class = $g->class || '';
$name = $g->name || '';
($name =~ /\S\s\S/)?(push @group, "$class '$name'"):(push @group,"$class $name");
}
# add exhaustive list of attributes
my $att = $self->attributes;
for ( keys %$att ) {
for my $v ( @{$att->{$_}} ) {
$v = qq("$v") if $v=~ /\S\s+\S/;
push @group, qq($_ $v);
}
}
my $group_field = join ' ; ',@group;
my $ref = $self->refseq;
my $n = ref($ref) ? $ref->name : $ref;
my $phase = $self->phase;
$phase = '.' unless defined $phase;
return join("\t",
$n,
$self->source,$self->method,
(defined $start ? $start : '.'),
(defined $stop ? $stop : '.'),
(defined $self->score ? $self->score : '.'),
(defined $strand ? $strand : '.'),
$phase,
$group_field);
}
=head2 gff3_string
Title : gff3_string
Usage : $string = $feature->gff3_string([$recurse])
Function: return GFF3 representation of feature
Returns : a string
Args : An optional flag, which if true, will cause the feature to recurse over
subfeatures.
Status : Public
=cut
sub gff3_string {
my $self = shift;
my ($recurse,$parent) = @_;
my ($start,$stop) = ($self->start,$self->stop);
# the defined() tests prevent uninitialized variable warnings, when dealing with clone objects
# whose endpoints may be undefined
($start,$stop) = ($stop,$start) if defined($start) && defined($stop) && $start > $stop;
my $strand = ('-','.','+')[$self->strand+1];
my $ref = $self->refseq;
my $n = ref($ref) ? $ref->name : $ref;
my $phase = $self->phase;
$phase = '.' unless defined $phase;
my ($class,$name) = ('','');
my @group;
if (my $g = $self->group) {
$class = $g->class || '';
$name = $g->name || '';
$name = "$class:$name" if defined $class;
push @group,[ID => $name] if !defined($parent) || $name ne $parent;
}
push @group,[Parent => $parent] if defined $parent && $parent ne '';
if (my $t = $self->target) {
$strand = '-' if $t->stop < $t->start;
push @group, $self->flatten_target($t,3);
}
my @attributes = $self->attributes;
while (@attributes) {
push @group,[shift(@attributes),shift(@attributes)]
}
my $group_field = join ';',map {join '=',_escape($_->[0]),_escape($_->[1])} @group;
my $string = join("\t",$n,$self->source,$self->method,$start||'.',$stop||'.',
$self->score||'.',$strand||'.',$phase,$group_field);
$string .= "\n";
if ($recurse) {
foreach ($self->sub_SeqFeature) {
$string .= $_->gff3_string(1,$name);
}
}
$string;
}
=head2 version
Title : version
Usage : $feature->version()
Function: get/set the GFF version to be returned by gff_string
Returns : the GFF version (default is 2)
Args : the GFF version (2, 2.5 of 3)
Status : Public
=cut
sub version {
my ($self, $version) = @_;
$self->{version} = $version if $version;
return $self->{version} || 2;
}
sub _escape {
my $toencode = shift;
( run in 0.645 second using v1.01-cache-2.11-cpan-39bf76dae61 )