CytoPosition is marker (Bio::Map::MarkerI compliant) with a location in a
cytogenetic map. See
Bio::Map::MarkerI for more information.
Cytogenetic locations are names of bands visible in stained mitotic
eucaryotic chromosomes. The naming follows strict rules which are
consistant at least in higher vertebates, e.g. mammals. The chromosome
name preceds the band names.
The shorter arm of the chromosome is called 'p' ('petit') and usually
drawn pointing up. The lower arm is called 'q' ('queue'). The bands
are named from the region separting these, a centromere (cen), towards
the tips or telomeric regions (ter) counting from 1 upwards. Depending
of the resolution used the bands are identified with one or more
digit. The first digit determines the major band and subsequent digits
sub bands: p1 band can be divided into subbands p11, p12 and 13 and
p11 can furter be divided into subbands p11.1 and p11.2. The dot after
second digit makes it easier to read the values. A region between ands
is given from the centromere outwards towards the telomere (e.g. 2p2-5
or 3p21-35) or from a band in the p arm to a band in the q arm.
sub cytorange
{ my ($self) = @_;
my ($chr, $r, $band, $band2, $arm, $arm2, $lc, $uc, $lcchar, $ucchar) = undef;
return $r if not defined $self->value; $self->value =~
m/([XY]|[0-9]+)(cen|qcen|pcen|[pq])?(ter|[.0-9]+)?-?([pq]?(cen|ter)?)?([.0-9]+)?/; $self->warn("Not a valid value: ". $self->value), return $r
if not defined $1 ;
$chr = uc $1;
$self->chr($chr);
$chr = 100 if $chr eq 'X';
$chr = 101 if $chr eq 'Y';
$chr *= 1000000;
$r = new Bio::Range();
$band = '';
if (defined $3 ) {
$2 || $self->throw("$& does not make sense: 'arm' or 'cen' missing");
$band = $3;
$band =~ tr/\.//d;
}
if (defined $6 ) {
$arm2 = $4;
$arm2 = $2 if $4 eq ''; $band2 = $6;
$band2 =~ tr/\.//d;
if ($band ne '' and (defined $arm2 and $2 ne $arm2 and $arm2 eq 'q') ) {
$lc = 'start'; $lcchar = '9';
$uc = 'end'; $ucchar = '9';
}
elsif ($band ne 'ter' and $2 ne $arm2 and $arm2 eq 'p') {
$lc = 'end'; $lcchar = '9';
$uc = 'start'; $ucchar = '9';
}
elsif ($band eq 'ter' and $arm2 eq 'p') {
$uc = 'start'; $ucchar = '9';
} elsif ($arm2 eq 'q') {
if (_pad($band, 5, '0') < _pad($band2, 5, '0')) {
$lc = 'start'; $lcchar = '0';
$uc = 'end'; $ucchar = '9';
} else {
$lc = 'end'; $lcchar = '9';
$uc = 'start'; $ucchar = '0';
}
}
elsif ($arm2 eq 'p') {
if (_pad($band, 5, '0') < _pad($band2, 5, '0')) {
$lc = 'end'; $lcchar = '0';
$uc = 'start'; $ucchar = '9';
} else {
$lc = 'start'; $lcchar = '9';
$uc = 'end'; $ucchar = '0';
}
}
else {
$self->throw("How did you end up here? $&");
}
if ( (defined $arm2 and $arm2 eq 'p') or (defined $arm2 and $arm2 eq 'p') ) {
$r->$uc(-(_pad($band2, 5, $ucchar)) + 100000 + $chr );
if (defined $3 and $3 eq 'ter') {
$r->end(200000 + $chr);
}
elsif ($2 eq 'cen' or $2 eq 'qcen' or $2 eq 'pcen'){
$r->$lc(100000 + $chr);
}
elsif ($2 eq 'q') {
$r->$lc(_pad($band, 5, $lcchar) + 100000 + $chr );
} else {
$r->$lc(-(_pad($band, 5, $lcchar)) + 100000 + $chr );
}
} else { $r->$uc(_pad($band2, 5, $ucchar) + 100000 + $chr);
if ($2 eq 'cen' or $2 eq 'pcen') {
$r->$lc(100000 + $chr);
}
elsif ($2 eq 'p') {
if ($3 eq 'ter') {
$r->$lc(200000 + $chr);
} else {
$r->$lc(-(_pad($band, 5, $lcchar)) + 100000 + $chr);
}
} else { $r->$lc(_pad($band, 5, $lcchar) + 100000 + $chr);
}
}
}
elsif (defined $4 and $4 ne '') {
if ($4 eq 'cen' || $4 eq 'qcen' || $4 eq 'pcen') { $r->end(100000 + $chr);
if ($2 eq 'p') {
if ($3 eq 'ter') {
$r->start($chr);
} else {
$r->start(_pad($band, 5, '9') + $chr);
}
}
elsif ($2 eq 'cen') {
$self->throw("'cen-cen' does not make sense: $&");
} else {
$self->throw("Only order p-cen is valid: $&");
}
}
elsif ($4 eq 'qter' || $4 eq 'ter') { $r->end(200000 + $chr);
if ($2 eq 'p'){
$r->start(-(_pad($band, 5, '9')) + 100000 + $chr); }
elsif ($2 eq 'q') {
$r->start(_pad($band, 5, '0') + 100000 + $chr);
}
elsif ($2 eq 'cen' || $2 eq 'qcen' || $2 eq 'pcen' ) {
$r->start(100000 + $chr);
}
}
elsif ($4 eq 'pter' ) {
$r->start( $chr);
if ($2 eq 'p'){
$r->end(-(_pad($band, 5, '0')) + 100000 + $chr);
}
elsif ($2 eq 'q') {
$r->end(_pad($band, 5, '9') + 100000 + $chr);
}
elsif ($2 eq 'cen' || $2 eq 'qcen' || $2 eq 'pcen' ) {
$r->end(100000 + $chr);
}
} else { $self->throw("lone '$4' in $& does not make sense");
}
}
elsif (defined $3 ) {
if ($2 eq 'p') {
if ($3 eq 'ter') { $r = new Bio::Range('-start' => $chr,
'-end' => $chr,
);
} else { $r = new Bio::Range('-start' => -(_pad($band, 5, '9')) + 100000 + $chr,
'-end' => -(_pad($band, 5, '0')) + 100000 + $chr,
);
}
} elsif ($2 eq 'q') {
if ($3 eq 'ter') { $r = new Bio::Range('-start' => 200000 + $chr,
'-end' => 200000 + $chr,
);
} else { $r = new Bio::Range('-start' => _pad($band, 5, '0') + 100000 + $chr,
'-end' => _pad($band, 5, '9') + 100000 + $chr,
);
}
} else { $self->throw("'cen' in $& does not make sense");
}
}
elsif (defined $2 ) { if ($2 eq'p' ) {
$r = new Bio::Range('-start' => $chr,
'-end' => 100000 + $chr
);
}
elsif ($2 eq'q' ) {
$r = new Bio::Range('-start' => 100000 + $chr,
'-end' => 200000 + $chr
);
} else { $r = new Bio::Range('-start' => 100000 + $chr,
'-end' => 100000 + $chr
);
}
}
else {
$r = new Bio::Range('-start' => $chr,
'-end' => 200000 + $chr
);
}
return $r; } |
sub range2value
{ my ($self,$value) = @_;
if( defined $value) {
if( ! $value->isa('Bio::Range') ) {
$self->throw("Is not a Bio::Range object but a [$value]");
return undef;
}
if( ! $value->start ) {
$self->throw("Start is not defined in [$value]");
return undef;
}
if( ! $value->end ) {
$self->throw("End is not defined in [$value]");
return undef;
}
if( $value->start < 100000 ) {
$self->throw("Start value has to be in millions, not ". $value->start);
return undef;
}
if( $value->end < 100000 ) {
$self->throw("End value has to be in millions, not ". $value->end);
return undef;
}
my ($chr, $arm, $band) = $value->start =~ /(\d+)(\d)(\d{5})/;
my ($chr2, $arm2, $band2) = $value->end =~ /(\d+)(\d)(\d{5})/;
my ($chrS, $armS, $bandS, $arm2S, $band2S, $sep) = ('', '', '', '', '', '' );
LOC: {
if ($chr == 100) {
$chrS = 'X';
}
elsif ($chr == 100) {
$chrS = 'Y';
} else {
$chrS = $chr;
}
last LOC if $arm == 0 and $arm2 == 2 and $band == 0 and $band2 == 0 ;
if ($arm == $arm2 ) {
if ($arm == 0) {
$armS = 'p';
$bandS = 'ter' if $band == 0;
}
elsif ($arm == 2) {
$armS = 'q';
$bandS = 'ter' if $band == 0;
} else {
$armS = 'q';
$armS = 'cen', if $band == 0; }
} else {
if ($arm == 0) {
$armS = 'p';
$arm2S = 'q';
$arm2S = '' if $band == 0 and $band2 == 0;
} else {
$armS = 'q';
$arm2S = 'p';
$arm2S = '' if $arm2 == 2 and $band == 0 and $band2 == 0;
}
}
last LOC if $band == $band2 ;
my $c;
if ($bandS ne 'ter') {
if ($armS eq 'p') {
$band = 100000 - $band;
$c = '9';
} else {
$c = '0';
}
$band =~ s/$c+$//;
$bandS = $band;
$bandS = substr($band, 0, 2). '.'. substr($band, 2) if length $band > 2;
}
last LOC unless $band2;
if ($arm2 == 0) {
$arm2S = 'p';
$band2 = 100000 - $band2;
$c = '0';
} else { $arm2S = 'q';
$c = '9';
}
if ($band2 == 0) {
if ($arm2 == 1) {
$arm2S = 'p';
$band2S = 'cen';
} else {
$band2S = 'ter';
}
last LOC;
}
last LOC if $band eq $band2 and $arm == $arm2;
$band2 =~ s/$c+$//;
$band2S = $band2;
$band2S = substr($band2, 0, 2). '.'. substr($band2, 2) if length $band2 > 2;
}
if ($armS eq 'p' and $arm2S eq 'p') {
my $tmp = $band2S;
$band2S = $bandS;
$bandS = $tmp;
}
$band2S = '' if $bandS eq $band2S ;
$armS = '' if $bandS eq 'cen';
$arm2S = '' if $armS eq $arm2S and $band2S ne 'ter';
$sep = '-' if $arm2S || $band2S;
$self->value( $chrS. $armS. $bandS. $sep. $arm2S. $band2S);
}
return $self->value; } |