2 # BioPerl module for Bio::Map::Position
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Sendu Bala <bix@sendu.me.uk>
8 # Copyright Jason Stajich
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
16 Bio::Map::Position - A single position of a Marker, or the range over which
17 that marker lies, in a Map
21 use Bio::Map::Position;
22 my $position = Bio::Map::Position->new(-map => $map,
27 my $position_with_range = Bio::Map::Position->new(-map => $map,
35 This object is an implementation of the PositionI interface that
36 handles the specific values of a position. This allows a map element
37 (e.g. Marker) to have multiple positions within a map and still be
38 treated as a single entity.
40 This handles the concept of a relative map in which the order of
41 elements and the distance between them is known, but does not
42 directly handle the case when distances are unknown - in that case
43 arbitrary values must be assigned for position values.
45 No units are assumed here - units are handled by context of which Map
46 a position is placed in or the subclass of this Position.
52 User feedback is an integral part of the evolution of this and other
53 Bioperl modules. Send your comments and suggestions preferably to
54 the Bioperl mailing list. Your participation is much appreciated.
56 bioperl-l@bioperl.org - General discussion
57 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
61 Please direct usage questions or support issues to the mailing list:
63 I<bioperl-l@bioperl.org>
65 rather than to the module maintainer directly. Many experienced and
66 reponsive experts will be able look at the problem and quickly
67 address it. Please include a thorough description of the problem
68 with code and data examples if at all possible.
72 Report bugs to the Bioperl bug tracking system to help us keep track
73 of the bugs and their resolution. Bug reports can be submitted via the
76 https://redmine.open-bio.org/projects/bioperl/
78 =head1 AUTHOR - Jason Stajich
80 Email jason@bioperl.org
84 Lincoln Stein, lstein@cshl.org
85 Heikki Lehvaslaiho, heikki-at-bioperl-dot-org
86 Chad Matsalla, bioinformatics1@dieselwurks.com
87 Sendu Bala, bix@sendu.me.uk
91 The rest of the documentation details each of the object methods.
92 Internal methods are usually preceded with a _
96 # Let the code begin...
98 package Bio
::Map
::Position
;
101 use Scalar
::Util
qw(looks_like_number);
102 use Bio
::Map
::Relative
;
104 use base
qw(Bio::Root::Root Bio::Map::PositionI);
109 Usage : my $obj = Bio::Map::Position->new();
110 Function: Builds a new Bio::Map::Position object
111 Returns : Bio::Map::Position
112 Args : -map => Bio::Map::MapI object
113 -element => Bio::Map::MappableI object
114 -relative => Bio::Map::RelativeI object
116 * If this position has no range, or if a single value can describe
118 -value => scalar : something that describes the single
119 point position or range of this
120 Position, most likely an int
122 * Or if this position has a range, at least two of *
123 -start => int : value of the start co-ordinate
124 -end => int : value of the end co-ordinate
125 -length => int : length of the range
130 my ($class, @args) = @_;
131 my $self = $class->SUPER::new
(@args);
133 my ($map, $marker, $element, $value, $start, $end, $length, $relative) =
134 $self->_rearrange([qw( MAP
144 my $do_range = defined($start) || defined($end);
145 if ($value && $do_range) {
146 $self->warn("-value and (-start|-end|-length) are mutually exclusive, ignoring value");
150 $map && $self->map($map);
151 $marker && $self->element($marker); # backwards compatibility
152 $element && $self->element($element);
153 $relative && $self->relative($relative);
154 defined($value) && $self->value($value);
157 defined($start) && $self->start($start);
158 defined($end) && $self->end($end);
160 if (defined($start) && ! defined($end)) {
161 $self->end($start + $length - 1);
163 elsif (! defined($start)) {
164 $self->start($end - $length + 1);
167 defined($self->end) || $self->end($start);
176 Usage : my $relative = $position->relative();
177 $position->relative($relative);
178 Function: Get/set the thing this Position's coordinates (numerical(), start(),
179 end()) are relative to, as described by a Relative object.
180 Returns : Bio::Map::RelativeI (default is one describing "relative to the
181 start of the Position's map")
182 Args : none to get, OR
183 Bio::Map::RelativeI to set
188 my ($self, $relative) = @_;
190 $self->throw("Must supply an object") unless ref($relative);
191 $self->throw("This is [$relative], not a Bio::Map::RelativeI") unless $relative->isa('Bio::Map::RelativeI');
192 $self->{_relative_not_implicit
} = 1;
193 $self->{_relative
} = $relative;
195 return $self->{_relative
} || $self->absolute_relative;
201 Usage : my $absolute = $position->absolute();
202 $position->absolute($absolute);
203 Function: Get/set how this Position's co-ordinates (numerical(), start(),
204 end()) are reported. When absolute is off, co-ordinates are
205 relative to the thing described by relative(). Ie. the value
206 returned by start() will be the same as the value you set start()
207 to. When absolute is on, co-ordinates are converted to be relative
208 to the start of the map.
210 So if relative() currently points to a Relative object describing
211 "relative to another position which is 100 bp from the start of
212 the map", this Position's start() had been set to 50 and absolute()
213 returns 1, $position->start() will return 150. If absolute() returns
214 0 in the same situation, $position->start() would return 50.
216 Returns : boolean (default 0)
217 Args : none to get, OR
224 if (@_) { $self->{_absolute
} = shift }
225 return $self->{_absolute
} || 0;
231 Usage : my $pos = $position->value;
232 Function: Get/Set the value for this postion
233 Returns : scalar, value
234 Args : [optional] new value to set
239 my ($self, $value) = @_;
240 if (defined $value) {
241 $self->{'_value'} = $value;
242 $self->start($self->numeric) unless defined($self->start);
243 $self->end($self->numeric) unless defined($self->end);
245 return $self->{'_value'};
251 Usage : my $num = $position->numeric;
252 Function: Read-only method that is guaranteed to return a numeric
253 representation of the start of this position.
254 Returns : scalar numeric
255 Args : none to get the co-ordinate normally (see absolute() method), OR
256 Bio::Map::RelativeI to get the co-ordinate converted to be
257 relative to what this Relative describes.
262 my ($self, $value) = @_;
263 my $num = $self->{'_value'};
264 $self->throw("The value has not been set, can't convert to numeric") unless defined($num);
265 $self->throw("This value [$num] is not numeric") unless looks_like_number
($num);
267 if (ref($value) && $value->isa('Bio::Map::RelativeI')) {
268 # get the value after co-ordinate conversion
270 my ($abs_start, $rel_start) = $self->_relative_handler($value);
271 return $abs_start + $raw - $rel_start;
274 # get the value as per absolute
275 if ($self->{_relative_not_implicit
} && $self->absolute) {
276 # this actually returns the start, but should be the same thing...
277 return $self->relative->absolute_conversion($self);
286 Usage : my $start = $position->start();
287 $position->start($start);
288 Function: Get/set the start co-ordinate of this position.
289 Returns : the start of this position
290 Args : scalar numeric to set, OR
291 none to get the co-ordinate normally (see absolute() method), OR
292 Bio::Map::RelativeI to get the co-ordinate converted to be
293 relative to what this Relative describes.
298 my ($self, $value) = @_;
299 if (defined $value) {
300 if (ref($value) && $value->isa('Bio::Map::RelativeI')) {
301 # get the value after co-ordinate conversion
302 my $raw = $self->{start
};
303 defined $raw || return;
304 my ($abs_start, $rel_start) = $self->_relative_handler($value);
305 return $abs_start + $raw - $rel_start;
309 $self->throw("This is [$value], not a number") unless looks_like_number
($value);
310 $self->{start
} = $value;
311 $self->value($value) unless defined($self->value);
315 # get the value as per absolute
316 if ($self->{_relative_not_implicit
} && $self->absolute) {
317 return $self->relative->absolute_conversion($self);
320 return defined($self->{start
}) ?
$self->{start
} : return;
326 Usage : my $end = $position->end();
327 $position->end($end);
328 Function: Get/set the end co-ordinate of this position.
329 Returns : the end of this position
330 Args : scalar numeric to set, OR
331 none to get the co-ordinate normally (see absolute() method), OR
332 Bio::Map::RelativeI to get the co-ordinate converted to be
333 relative to what this Relative describes.
338 my ($self, $value) = @_;
339 if (defined $value) {
340 if (ref($value) && $value->isa('Bio::Map::RelativeI')) {
341 # get the value after co-ordinate conversion
342 my $raw = $self->{end
};
343 defined $raw || return;
344 my ($abs_start, $rel_start) = $self->_relative_handler($value);
345 return $abs_start + $raw - $rel_start;
349 $self->throw("This value [$value] is not numeric!") unless looks_like_number
($value);
350 $self->{end
} = $value;
354 # get the value as per absolute
355 if ($self->{_relative_not_implicit
} && $self->absolute) {
356 my $raw = $self->{end
} || return;
357 my $abs_start = $self->relative->absolute_conversion($self) || return;
358 return $abs_start + ($raw - $self->{start
});
361 return defined($self->{end
}) ?
$self->{end
} : return;
367 Usage : $length = $position->length();
368 Function: Get/set the length of this position's range, changing the end() if
369 necessary. Getting and even setting the length will fail if both
370 start() and end() are not already defined.
371 Returns : the length of this range
372 Args : none to get, OR scalar numeric (>0) to set.
377 my ($self, $length) = @_;
379 $length > 0 || return;
380 my $existing_length = $self->length || return;
381 return $length if $existing_length == $length;
382 $self->end($self->{start
} + $length - 1);
385 if (defined($self->start) && defined($self->end)) {
386 return $self->end - $self->start + 1;
394 Usage : my $num = $position->sortable();
395 Function: Read-only method that is guaranteed to return a value suitable
396 for correctly sorting this kind of position amongst other positions
397 of the same kind on the same map. Note that sorting different kinds
398 of position together is unlikely to give sane results.
405 my ($self, $given_map) = @_;
406 my $answer = $self->numeric($self->absolute_relative);
413 Usage : print $position->toString(), "\n";
414 Function: stringifies this range
415 Returns : a string representation of the range of this Position
416 Args : optional Bio::Map::RelativeI to have the co-ordinates reported
417 relative to the thing described by that Relative
422 my ($self, $rel) = @_;
423 if (defined($self->start) && defined($self->end)) {
424 return $self->start($rel).'..'.$self->end($rel);
429 =head2 absolute_relative
431 Title : absolute_relative
432 Usage : my $rel = $position->absolute_relative();
433 Function: Get a relative describing the start of the map. This is useful for
434 supplying to the coordinate methods (start(), end() etc.) to get
435 the temporary effect of having set absolute(1).
436 Returns : Bio::Map::Relative
441 sub absolute_relative
{
442 return Bio
::Map
::Relative
->new(-map => 0, -description
=> 'start of map');
445 # get our own absolute start and that of the thing we want as a frame of
447 sub _relative_handler
{
448 my ($self, $value) = @_;
450 my $own_relative = $self->relative;
452 # if the requested relative position is the same as the actual
453 # relative, the current co-ordinate values are correct so shortcut
454 my ($own_type, $req_type) = ($own_relative->type, $value->type);
455 if ($own_type && $req_type && $own_type eq $req_type && $own_relative->$own_type eq $value->$req_type) {
459 my $abs_start = $own_relative->absolute_conversion($self);
460 my $rel_start = $value->absolute_conversion($self);
461 $self->throw("Unable to resolve co-ordinate because relative to something that ultimately isn't relative to the map start")
462 unless defined($abs_start) && defined($rel_start);
464 return ($abs_start, $rel_start);