Add tests for memory leaks and weaken for Issue #81
[bioperl-live.git] / Bio / Map / Physical.pm
blobd6429ac3842082bd96e54c74fea5d80c2315017a
2 # BioPerl module for Bio::Map::Physical
4 # Please direct questions and support issues to <bioperl-l@bioperl.org>
6 # Cared for by Sendu Bala <bix@sendu.me.uk>
8 # Copyright AGCoL
10 # You may distribute this module under the same terms as perl itself
12 # POD documentation - main docs before the code
14 =head1 NAME
16 Bio::Map::Physical - A class for handling a Physical Map (such as FPC)
18 =head1 SYNOPSIS
20 use Bio::MapIO;
22 # accquire a Bio::Map::Physical using Bio::MapIO::fpc
23 my $mapio = Bio::MapIO->new(-format => "fpc",-file => "rice.fpc",
24 -readcor => 0);
26 my $physical = $mapio->next_map();
28 # get all the markers ids
29 foreach my $marker ( $physical->each_markerid() ) {
30 print "Marker $marker\n";
32 # acquire the marker object using Bio::Map::FPCMarker
33 my $markerobj = $physical->get_markerobj($marker);
35 # get all the clones hit by this marker
36 foreach my $clone ($markerobj->each_cloneid() ) {
37 print " +++$clone\n";
41 =head1 DESCRIPTION
43 This class is basically a continer class for a collection of Contig maps and
44 other physical map information.
46 Bio::Map::Physical has been tailored to work for FPC physical maps, but
47 could probably be used for others as well (with the appropriate MapIO
48 module).
50 This class also has some methods with specific functionalities:
52 print_gffstyle() : Generates GFF; either Contigwise[Default] or
53 Groupwise
55 print_contiglist() : Prints the list of Contigs, markers that hit the
56 contig, the global position and whether the marker
57 is a placement (<P>) or a Framework (<F>) marker.
59 print_markerlist() : Prints the markers list; contig and corresponding
60 number of clones.
62 matching_bands() : Given two clones [and tolerence], this method
63 calculates how many matching bands do they have.
65 coincidence_score() : Given two clones [,tolerence and gellen], this
66 method calculates the Sulston Coincidence score.
68 For faster access and better optimization, the data is stored internally in
69 hashes. The corresponding objects are created on request.
71 =head1 FEEDBACK
73 =head2 Mailing Lists
75 User feedback is an integral part of the evolution of this and other
76 Bioperl modules. Send your comments and suggestions preferably to
77 the Bioperl mailing list. Your participation is much appreciated.
79 bioperl-l@bioperl.org - General discussion
80 http://bioperl.org/wiki/Mailing_lists - About the mailing lists
82 =head2 Support
84 Please direct usage questions or support issues to the mailing list:
86 I<bioperl-l@bioperl.org>
88 rather than to the module maintainer directly. Many experienced and
89 reponsive experts will be able look at the problem and quickly
90 address it. Please include a thorough description of the problem
91 with code and data examples if at all possible.
93 =head2 Reporting Bugs
95 Report bugs to the Bioperl bug tracking system to help us keep track
96 of the bugs and their resolution. Bug reports can be submitted via the
97 web:
99 https://github.com/bioperl/bioperl-live/issues
101 =head1 AUTHOR - Gaurav Gupta
103 Email gaurav@genome.arizona.edu
105 =head1 CONTRIBUTORS
107 Sendu Bala bix@sendu.me.uk
109 =head1 PROJECT LEADERS
111 Jamie Hatfield jamie@genome.arizona.edu
112 Dr. Cari Soderlund cari@genome.arizona.edu
114 =head1 PROJECT DESCRIPTION
116 The project was done in Arizona Genomics Computational Laboratory (AGCoL)
117 at University of Arizona.
119 This work was funded by USDA-IFAFS grant #11180 titled "Web Resources for
120 the Computation and Display of Physical Mapping Data".
122 For more information on this project, please refer:
123 http://www.genome.arizona.edu
125 =head1 APPENDIX
127 The rest of the documentation details each of the object methods.
128 Internal methods are usually preceded with a _
130 =cut
132 # Let the code begin...
134 package Bio::Map::Physical;
135 use vars qw($MAPCOUNT);
136 use strict;
137 use POSIX;
139 use Bio::Map::Clone;
140 use Bio::Map::Contig;
141 use Bio::Map::FPCMarker;
143 use base qw(Bio::Map::SimpleMap);
144 BEGIN { $MAPCOUNT = 1; }
146 =head1 Access Methods
148 These methods let you get and set the member variables
150 =head2 version
152 Title : version
153 Usage : my $version = $map->version();
154 Function: Get/set the version of the program used to
155 generate this map
156 Returns : scalar representing the version
157 Args : none to get, OR string to set
159 =cut
161 sub version {
162 my ($self,$value) = @_;
163 if (defined($value)) {
164 $self->{'_version'} = $value;
166 return $self->{'_version'};
169 =head2 modification_user
171 Title : modification_user
172 Usage : my $modification_user = $map->modification_user();
173 Function: Get/set the name of the user who last modified this map
174 Returns : scalar representing the username
175 Args : none to get, OR string to set
177 =cut
179 sub modification_user {
180 my ($self,$value) = @_;
181 if (defined($value)) {
182 $self->{'_modification_user'} = $value;
184 return $self->{'_modification_user'};
187 =head2 group_type
189 Title : group_type
190 Usage : $map->group_type($grptype);
191 my $grptype = $map->group_type();
192 Function: Get/set the group type of this map
193 Returns : scalar representing the group type
194 Args : none to get, OR string to set
196 =cut
198 sub group_type {
199 my ($self,$value) = @_;
200 if (defined($value)) {
201 $self->{'_grouptype'} = $value;
203 return $self->{'_grouptype'};
206 =head2 group_abbr
208 Title : group_abbr
209 Usage : $map->group_abbr($grpabbr);
210 my $grpabbr = $map->group_abbr();
211 Function: get/set the group abbrev of this map
212 Returns : string representing the group abbrev
213 Args : none to get, OR string to set
215 =cut
217 sub group_abbr {
218 my ($self,$value) = @_;
219 if (defined($value)) {
220 $self->{'_groupabbr'} = $value;
222 return $self->{'_groupabbr'};
225 =head2 core_exists
227 Title : core_exists
228 Usage : my $core_exists = $map->core_exists();
229 Function: Get/set if the FPC file is accompanied by COR file
230 Returns : boolean
231 Args : none to get, OR 1|0 to set
233 =cut
235 sub core_exists {
236 my ($self,$value) = @_;
237 if (defined($value)) {
238 $self->{'_corexists'} = $value ? 1 : 0;
240 return $self->{'_corexists'};
243 =head2 each_cloneid
245 Title : each_cloneid
246 Usage : my @clones = $map->each_cloneid();
247 Function: returns an array of clone names
248 Returns : list of clone names
249 Args : none
251 =cut
253 sub each_cloneid {
254 my ($self) = @_;
255 return keys %{$self->{'_clones'}};
258 =head2 get_cloneobj
260 Title : get_cloneobj
261 Usage : my $cloneobj = $map->get_cloneobj('CLONEA');
262 Function: returns an object of the clone given in the argument
263 Returns : object of the clone
264 Args : scalar representing the clone name
266 =cut
268 sub get_cloneobj {
269 my ($self,$clone) = @_;
271 return 0 if(!defined($clone));
272 return if($clone eq "");
273 return if(!exists($self->{'_clones'}{$clone}));
275 my ($type,$contig,$bands,$gel,$group,$remark,$fp_number);
276 my ($sequence_type,$sequence_status,$fpc_remark,@amatch,@pmatch,@ematch,
277 $startrange,$endrange);
278 my %clones = %{$self->{'_clones'}{$clone}};
279 my @markers;
281 if (ref($clones{'clone'}) eq 'Bio::Map::Clone') {
282 return $clones{'clone'};
285 $type = $clones{'type'} if (exists($clones{'type'}));
286 @markers = (keys %{$clones{'markers'}}) if (exists($clones{'markers'}));
287 $contig = $clones{'contig'} if (exists($clones{'contig'}));
288 $bands = $clones{'bands'} if (exists($clones{'bands'}));
289 $gel = $clones{'gel'} if (exists($clones{'gel'}));
290 $group = $clones{'group'} if (exists($clones{'group'}));
291 $remark = $clones{'remark'} if (exists($clones{'remark'}));
293 $fp_number = $clones{'fp_number'} if (exists($clones{'fp_number'}));
294 $fpc_remark = $clones{'fpc_remark'} if (exists($clones{'fpc_remark'}));
296 $sequence_type = $clones{'sequence_type'}
297 if (exists($clones{'sequence_type'}));
298 $sequence_status = $clones{'sequence_status'}
299 if (exists($clones{'sequence_status'} ));
301 @amatch = (keys %{$clones{'matcha'}}) if (exists($clones{'matcha'}));
302 @ematch = (keys %{$clones{'matche'}}) if (exists($clones{'matche'}));
303 @pmatch = (keys %{$clones{'matchp'}}) if (exists($clones{'matchp'}));
305 $startrange = $clones{'range'}{'start'}
306 if (exists($clones{'range'}{'start'}));
307 $endrange = $clones{'range'}{'end'}
308 if (exists($clones{'range'}{'end'}));
310 #*** why doesn't it call Bio::Map::Clone->new ? Seems dangerous...
311 my $cloneobj = bless( {
312 _name => $clone,
313 _markers => \@markers,
314 _contig => $contig,
315 _type => $type,
316 _bands => $bands,
317 _gel => $gel,
318 _group => $group,
319 _remark => $remark,
320 _fpnumber => $fp_number,
321 _sequencetype => $sequence_type,
322 _sequencestatus => $sequence_status,
323 _fpcremark => $fpc_remark,
324 _matche => \@ematch,
325 _matcha => \@amatch,
326 _matchp => \@pmatch,
327 _range => Bio::Range->new(-start => $startrange,
328 -end => $endrange),
329 }, 'Bio::Map::Clone');
331 $self->{'_clones'}{$clone}{'clone'} = $cloneobj;
332 return $cloneobj;
335 =head2 each_markerid
337 Title : each_markerid
338 Usage : my @markers = $map->each_markerid();
339 Function: returns list of marker names
340 Returns : list of marker names
341 Args : none
343 =cut
345 sub each_markerid {
346 my ($self) = @_;
347 return keys (%{$self->{'_markers'}});
350 =head2 get_markerobj
352 Title : get_markerobj
353 Usage : my $markerobj = $map->get_markerobj('MARKERA');
354 Function: returns an object of the marker given in the argument
355 Returns : object of the marker
356 Args : scalar representing the marker name
358 =cut
360 sub get_markerobj {
361 my ($self,$marker) = @_;
363 return 0 if(!defined($marker));
364 return if($marker eq "");
365 return if(!exists($self->{'_markers'}{$marker}));
367 my ($global,$framework,$group,$anchor,$remark,$type,$linkage,$subgroup);
368 my %mkr = %{$self->{'_markers'}{$marker}};
370 return $mkr{'marker'} if (ref($mkr{'marker'}) eq 'Bio::Map::FPCMarker');
372 $type = $mkr{'type'} if(exists($mkr{'type'}));
373 $global = $mkr{'global'} if(exists($mkr{'global'} ));
374 $framework = $mkr{'framework'} if(exists($mkr{'framework'}));
375 $anchor = $mkr{'anchor'} if(exists($mkr{'anchor'}));
376 $group = $mkr{'group'} if(exists($mkr{'group'}));
377 $subgroup = $mkr{'subgroup'} if(exists($mkr{'subgroup'}));
378 $remark = $mkr{'remark'} if(exists($mkr{'remark'}));
380 my %clones = %{$mkr{'clones'}};
381 my %contigs = %{$mkr{'contigs'}};
383 my %markerpos = %{$mkr{'posincontig'}} if(exists($mkr{'posincontig'}));
385 #*** why doesn't it call Bio::Map::FPCMarker->new ? Seems dangerous...
386 my $markerobj = bless( {
387 _name => $marker,
388 _type => $type,
389 _global => $global,
390 _frame => $framework,
391 _group => $group,
392 _subgroup => $subgroup,
393 _anchor => $anchor,
394 _remark => $remark,
395 _clones => \%clones,
396 _contigs => \%contigs,
397 _position => \%markerpos,
398 }, 'Bio::Map::FPCMarker');
400 $self->{'_markers'}{$marker}{'marker'} = $markerobj;
401 return $markerobj;
404 =head2 each_contigid
406 Title : each_contigid
407 Usage : my @contigs = $map->each_contigid();
408 Function: returns a list of contigs (numbers)
409 Returns : list of contigs
410 Args : none
412 =cut
414 sub each_contigid {
415 my ($self) = @_;
416 return keys (%{$self->{'_contigs'}});
419 =head2 get_contigobj
421 Title : get_contigobj
422 Usage : my $contigobj = $map->get_contigobj('CONTIG1');
423 Function: returns an object of the contig given in the argument
424 Returns : object of the contig
425 Args : scalar representing the contig number
427 =cut
429 sub get_contigobj {
430 my ($self,$contig) = @_;
432 return 0 if(!defined($contig));
433 return if($contig eq "");
434 return if(!exists($self->{'_contigs'}{$contig}));
436 my ($group,$anchor,$uremark,$tremark,$cremark,$startrange,$endrange,
437 $linkage,$subgroup);
438 my %ctg = %{$self->{'_contigs'}{$contig}};
439 my (%position, %pos);
441 return $ctg{'contig'} if (ref($ctg{'contig'}) eq 'Bio::Map::Contig');
443 $group = $ctg{'group'} if (exists($ctg{'group'}));
444 $subgroup = $ctg{'subgroup'} if (exists($ctg{'subgroup'}));
445 $anchor = $ctg{'anchor'} if (exists($ctg{'anchor'}));
446 $cremark = $ctg{'chr_remark'} if (exists($ctg{'chr_remark'}));
447 $uremark = $ctg{'usr_remark'} if (exists($ctg{'usr_remark'}));
448 $tremark = $ctg{'trace_remark'} if (exists($ctg{'trace_remark'}));
450 $startrange = $ctg{'range'}{'start'}
451 if (exists($ctg{'range'}{'start'}));
452 $endrange = $ctg{'range'}{'end'}
453 if (exists($ctg{'range'}{'end'}));
455 my %clones = %{$ctg{'clones'}} if (exists($ctg{'clones'}));
456 my %markers = %{$ctg{'markers'}} if (exists($ctg{'markers'}));
458 my $pos = $ctg{'position'};
460 #*** why doesn't it call Bio::Map::Contig->new ? Seems dangerous...
461 my $contigobj = bless( {
462 _group => $group,
463 _subgroup => $subgroup,
464 _anchor => $anchor,
465 _markers => \%markers,
466 _clones => \%clones,
467 _name => $contig,
468 _cremark => $cremark,
469 _uremark => $uremark,
470 _tremark => $tremark,
471 _position => $pos,
472 _range => Bio::Range->new(-start => $startrange,
473 -end => $endrange),
474 }, 'Bio::Map::Contig');
476 $self->{'_contigs'}{$contig}{'contig'} = $contigobj;
477 return $contigobj;
480 =head2 matching_bands
482 Title : matching_bands
483 Usage : $self->matching_bands('cloneA','cloneB',[$tol]);
484 Function: given two clones [and tolerence], this method calculates how many
485 matching bands do they have.
486 (this method is ported directly from FPC)
487 Returns : scalar representing the number of matching bands
488 Args : names of the clones ('cloneA', 'cloneB') [Default tolerence=7]
490 =cut
492 sub matching_bands {
493 my($self,$cloneA,$cloneB,$tol) = @_;
494 my($lstart,$kband,$match,$diff,$i,$j);
496 return 0 if(!defined($cloneA) || !defined($cloneB) ||
497 !($self->core_exists()));
499 $tol = 7 if (!defined($tol));
501 my %_clones = %{$self->{'_clones'}};
503 my @bandsA = @{$_clones{$cloneA}{'bands'}};
504 my @bandsB = @{$_clones{$cloneB}{'bands'}};
506 $match = 0;
507 $lstart = 0;
509 for ($i=0; $i<scalar(@bandsA);$i++) {
510 $kband = $bandsA[$i];
511 for ($j = $lstart; $j<scalar(@bandsB); $j++) {
512 $diff = $kband - $bandsB[$j];
513 if (abs($diff) <= $tol ) {
514 $match++;
515 $lstart = $j+1;
516 last;
518 elsif ($diff < 0) {
519 $lstart = $j;
520 last;
524 return $match;
527 =head2 coincidence_score
529 Title : coincidence_score
530 Usage : $self->coincidence_score('cloneA','cloneB'[,$tol,$gellen]);
531 Function: given two clones [,tolerence and gellen], this method calculates
532 the Sulston Coincidence score.
533 (this method is ported directly from FPC)
534 Returns : scalar representing the Sulston coincidence score.
535 Args : names of the clones ('cloneA', 'cloneB')
536 [Default tol=7 gellen=3300.0]
538 =cut
540 sub coincidence_score {
541 my($self,$cloneA,$cloneB,$tol,$gellen) = @_;
543 return 0 if(!defined($cloneA) || !defined($cloneB) ||
544 !($self->core_exists()));
546 my %_clones = %{$self->{'_clones'}};
548 my $numbandsA = scalar(@{$_clones{$cloneA}{'bands'}});
549 my $numbandsB = scalar(@{$_clones{$cloneB}{'bands'}});
551 my ($nL,$nH,$m,$i,$psmn,$pp,$pa,$pb,$t,$c,$a,$n);
552 my @logfact;
553 my $score;
555 $gellen = 3300.0 if (!defined($gellen));
556 $tol = 7 if (!defined($tol));
558 if ($numbandsA > $numbandsB) {
559 $nH = $numbandsA;
560 $nL = $numbandsB;
562 else {
563 $nH = $numbandsB;
564 $nL = $numbandsA;
567 $m = $self->matching_bands($cloneA, $cloneB,$tol);
569 $logfact[0] = 0.0;
570 $logfact[1] = 0.0;
571 for ($i=2; $i<=$nL; $i++) {
572 $logfact[$i] = $logfact[$i - 1] + log($i);
575 $psmn = 1.0 - ((2*$tol)/$gellen);
577 $pp = $psmn ** $nH;
578 $pa = log($pp);
579 $pb = log(1 - $pp);
580 $t = 1e-37;
582 for ($n = $m; $n <= $nL; $n++) {
583 $c = $logfact[$nL] - $logfact[$nL - $n] - $logfact[$n];
584 $a = exp($c + ($n * $pb) + (($nL - $n) * $pa));
585 $t += $a;
588 $score = sprintf("%.e",$t);
589 return $score;
592 =head2 print_contiglist
594 Title : print_contiglist
595 Usage : $map->print_contiglist([showall]); #[Default 0]
596 Function: prints the list of contigs, markers that hit the contig, the
597 global position and whether the marker is a placement (P) or
598 a Framework (F) marker.
599 Returns : none
600 Args : [showall] [Default 0], 1 includes all the discrepant markers
602 =cut
604 sub print_contiglist{
605 my ($self,$showall) = @_;
606 my $pos;
608 $showall = 0 if (!defined($showall));
609 my %_contigs = %{$self->{'_contigs'}};
610 my %_markers = %{$self->{'_markers'}};
611 my %_clones = %{$self->{'_clones'}};
613 my @contigs = $self->each_contigid();
614 my @sortedcontigs = sort {$a <=> $b } @contigs;
616 print "\n\nContig List\n\n";
617 foreach my $contig (@sortedcontigs) {
618 my %list;
619 my %alist;
621 my $ctgAnchor = $_contigs{$contig}{'anchor'};
622 my $ctgGroup = $_contigs{$contig}{'group'};
624 my @mkr = keys ( %{$_contigs{$contig}{'markers'}} );
626 foreach my $marker (@mkr) {
627 my $mrkGroup = $_markers{$marker}{'group'};
628 my $mrkGlobal = $_markers{$marker}{'global'};
629 my $mrkFramework = $_markers{$marker}{'framework'};
630 my $mrkAnchor = $_markers{$marker}{'anchor'};
632 if($ctgGroup =~ /\d+|\w/ && $ctgGroup != 0) {
633 if ($mrkGroup eq $ctgGroup) {
634 if ($mrkFramework == 0) {
635 $pos = $mrkGlobal."P";
637 else {
638 $pos = $mrkGlobal."F";
640 $list{$marker} = $pos;
642 elsif ($showall == 1) {
643 my $chr = $self->group_abbr().$mrkGroup;
644 $alist{$marker} = $chr;
647 elsif ($showall == 1 && $ctgGroup !~ /\d+/) {
648 my $chr = $self->group_abbr().$mrkGroup;
649 $alist{$marker} = $chr;
653 my $chr = $ctgGroup;
654 $chr = $self->group_abbr().$ctgGroup if ($ctgGroup =~ /\d+|\w/);
656 if ($showall == 1 ) {
658 print " ctg$contig ", $chr, " "
659 if ($_contigs{$contig}{'group'} !~ /\d+|\w/);
661 elsif ($ctgGroup =~ /\d+|\w/ && $ctgGroup ne 0){
662 print " ctg",$contig, " ",$chr, " ";
665 while (my ($k,$v) = each %list) {
666 print "$k/$v ";
669 print "\n" if ($showall == 0 && $ctgGroup =~ /\d+|\w/ &&
670 $ctgGroup ne 0 );
672 if ($showall == 1) {
673 while (my ($k,$v) = each %alist) {
674 print "$k/$v ";
676 print "\n";
681 =head2 print_markerlist
683 Title : print_markerlist
684 Usage : $map->print_markerlist();
685 Function : prints the marker list; contig and corresponding number of
686 clones for each marker.
687 Returns : none
688 Args : none
690 =cut
692 sub print_markerlist {
693 my ($self) = @_;
695 my %_contigs = %{$self->{'_contigs'}};
696 my %_markers = %{$self->{'_markers'}};
697 my %_clones = %{$self->{'_clones'}};
699 print "Marker List\n\n";
701 foreach my $marker ($self->each_markerid()) {
702 print " ",$marker, " ";
704 my %list;
705 my %mclones = %{$_markers{$marker}{'clones'}};
707 foreach my $clone (%mclones) {
708 if (exists($_clones{$clone}{'contig'}) ) {
709 my $ctg = $_clones{$clone}{'contig'};
711 if (exists($list{$ctg})) {
712 my $clonehits = $list{$ctg};
713 $clonehits++;
714 $list{$ctg} = $clonehits;
716 else {
717 $list{$ctg} = 1;
721 while (my ($k,$v) = each %list) {
722 print "$k/$v ";
724 print "\n";
728 =head2 print_gffstyle
730 Title : print_gffstyle
731 Usage : $map->print_gffstyle([style]);
732 Function : prints GFF; either Contigwise (default) or Groupwise
733 Returns : none
734 Args : [style] default = 0 contigwise, else
735 1 groupwise (chromosome-wise).
737 =cut
739 sub print_gffstyle {
740 my ($self,$style) = @_;
742 $style = 0 if(!defined($style));
744 my %_contigs = %{$self->{'_contigs'}};
745 my %_markers = %{$self->{'_markers'}};
746 my %_clones = %{$self->{'_clones'}};
748 my $i;
749 my ($depth, $save_depth);
750 my ($x, $y);
751 my @stack;
752 my ($k, $j, $s);
753 my $pos;
754 my $contig;
756 # Calculate the position for the marker in the contig
758 my @contigs = $self->each_contigid();
759 my @sortedcontigs = sort {$a <=> $b } @contigs;
760 my $offset = 0;
761 my %gffclones;
762 my %gffcontigs;
763 my %gffmarkers;
764 my $basepair = 4096;
766 foreach my $contig (@sortedcontigs) {
767 if($_contigs{$contig}{'range'} ) {
768 $offset = $_contigs{$contig}{'range'}{'start'};
770 if ($offset <= 0){
771 $offset = $offset * -1;
772 $gffcontigs{$contig}{'start'} = 1;
773 $gffcontigs{$contig}{'end'} =
774 ($_contigs{$contig}{'range'}{'end'} +
775 $offset ) * $basepair + 1;
777 else {
778 $offset = 0;
779 $gffcontigs{$contig}{'start'} =
780 $_contigs{$contig}{'range'}{'start'} * $basepair;
781 $gffcontigs{$contig}{'end'} =
782 $_contigs{$contig}{'range'}{'end'} * $basepair;
785 else {
786 $gffcontigs{$contig}{'start'} = 1;
787 $gffcontigs{$contig}{'end'} = 1;
790 my @clones = keys %{$_contigs{$contig}{'clones'}};
791 foreach my $clone (@clones) {
792 if(exists ($_clones{$clone}{'range'}) ) {
793 my $gffclone = $clone;
795 $gffclone =~ s/sd1$//;
797 $gffclones{$gffclone}{'start'} =
798 (($_clones{$clone}{'range'}{'start'} + $offset) *
799 $basepair + 1);
801 $gffclones{$gffclone}{'end'} =
802 (($_clones{$clone}{'range'}{'end'}
803 + $offset) * $basepair + 1);
806 if(!$contig) {
807 my %markers = %{$_clones{$clone}{'markers'}}
808 if (exists($_clones{$clone}{'markers'}));
810 while (my ($k,$v) = each %markers) {
811 $gffmarkers{$contig}{$k} =
812 ( ( $_clones{$clone}{'range'}{'start'} +
813 $_clones{$clone}{'range'}{'end'} ) / 2 ) *
814 $basepair + 1 ;
819 if($contig) {
820 my %markers = %{$_contigs{$contig}{'markers'}}
821 if (exists($_contigs{$contig}{'markers'}));
823 while (my ($k,$v) = each %markers) {
824 $gffmarkers{$contig}{$k} = ($v + $offset) * $basepair + 1;
829 if (!$style) {
830 foreach my $contig (@sortedcontigs) {
832 if(exists ($_contigs{$contig}{'range'} ) ) {
833 print join("\t","ctg$contig","assembly","contig",
834 $gffcontigs{$contig}{'start'},
835 $gffcontigs{$contig}{'end'},".",".",".",
836 "Sequence \"ctg$contig\"; Name \"ctg$contig\"\n"
840 my @clones = (keys %{$_contigs{$contig}{'clones'}} );
842 foreach my $clone (@clones) {
843 if(exists ($_clones{$clone}{'range'}) ) {
844 print join("\t","ctg$contig","FPC");
846 my $type = $_clones{$clone}{'type'};
848 if($clone =~ /sd1$/) {
849 $clone =~ s/sd1$//;
850 $type = "sequenced";
852 print join ("\t","\t$type",$gffclones{$clone}{'start'},
853 $gffclones{$clone}{'end'},".",".",".",
854 "$type \"$clone\"; Name \"$clone\"");
856 my @markers = keys %{$_clones{$clone}{'markers'}};
857 print "; Marker_hit" if (scalar(@markers));
859 foreach my $mkr(@markers) {
860 if (exists($_markers{$mkr}{'framework'})) {
861 print " \"$mkr ",$_markers{$mkr}{'group'}," ",
862 $_markers{$mkr}{'global'},"\"";
864 else {
865 print " \"$mkr 0 0\"";
868 print "; Contig_hit \"",$_clones{$clone}{'contig'},"\" "
869 if (defined($_clones{$clone}{'contig'}));
871 print "\n";
874 if (exists ($_contigs{$contig}{'markers'}) ) {
875 my %list = %{$_contigs{$contig}{'markers'}};
877 while (my ($k,$v) = each %list) {
878 print "ctg", $contig, "\tFPC\t";
879 my $position = $gffmarkers{$contig}{$k};
881 my $type = "marker";
883 $type = "electronicmarker"
884 if ($_markers{$k}{'type'} eq "eMRK");
886 if( exists($_markers{$k}{'framework'})) {
887 $type = "frameworkmarker"
888 if($_markers{$k}{'framework'} == 1);
890 $type = "placementmarker"
891 if($_markers{$k}{'framework'} == 0);
894 print join ("\t","$type",$position,$position,".",".",
895 ".","$type \"$k\"; Name \"$k\"");
897 my @clonelist;
898 my @clones = keys %{$_markers{$k}{'clones'}};
900 foreach my $cl (@clones) {
901 push (@clonelist, $cl)
902 if($_clones{$cl}{'contig'} == $contig);
905 $" = " ";
906 print("; Contig_hit \"ctg$contig - ",scalar(@clonelist),
907 "\" (@clonelist)\n");
912 else {
913 my %_groups;
914 my $margin = 2 * $basepair;
915 my $displacement = 0;
916 my @grouplist;
918 foreach my $contig (@sortedcontigs) {
919 my $recordchr;
920 my $chr = $_contigs{$contig}{'group'};
921 $chr = 0 if ($chr !~ /\d+|\w+/);
923 $recordchr->{group} = $chr;
924 $recordchr->{contig} = $contig;
925 $recordchr->{position} = $_contigs{$contig}{'position'};
927 push @grouplist, $recordchr;
930 my @chr = keys (%{$_groups{'group'}});
931 my @sortedchr;
933 if ($self->group_type eq 'Chromosome') {
934 @sortedchr = sort { $a->{'group'} <=> $b->{'group'}
936 $a->{'contig'} <=> $b->{'contig'}
937 } @grouplist;
939 else {
940 @sortedchr = sort { $a->{'group'} cmp $b->{'group'}
942 $a->{'contig'} cmp $b->{'contig'}
943 } @grouplist;
945 my $lastchr = -1;
946 my $chrend = 0;
948 foreach my $chr (@sortedchr) {
949 my $chrname = $self->group_abbr().$chr->{'group'};
951 if ($lastchr eq -1 || $chr->{'group'} ne $lastchr ) {
952 $lastchr = $chr->{'group'} if ($lastchr eq -1);
953 $displacement = 0;
955 # caluclate the end position of the contig
956 my $ctgcount = 0;
957 my $prevchr = 0;
958 $chrend = 0;
960 if ($chr->{contig} != 0) {
961 foreach my $ch (@sortedchr) {
962 if ($ch->{'group'} eq $chr->{'group'}) {
963 if($ch->{'contig'} != 0) {
964 my $ctg = $ch->{'contig'}
965 if($ch->{'contig'} != 0);
967 $chrend += $gffcontigs{$ctg}->{'end'};
968 ++$ctgcount;
972 $chrend += ($ctgcount-1) * $margin;
974 else {
975 $chrend = $gffcontigs{'0'}->{'end'};
978 $chrname = $self->group_abbr()."ctg0"
979 if ($chr->{'contig'} == 0);
981 print join ("\t", $chrname,"assembly","Chromosome",1,
982 "$chrend",".",".",".",
983 "Sequence \"$chrname\"; Name \"$chrname\"\n");
986 print join ("\t", $chrname,"assembly","Chromosome",1,
987 "$chrend",".",".",".",
988 "Sequence \"$chrname\"; Name \"$chrname\"\n")
989 if ($chr->{'group'} ne $lastchr && $chr->{'group'} eq 0 );
991 $lastchr = $chr->{'group'};
992 $lastchr = -1 if ($chr->{'contig'} == 0);
994 my $contig = $chr->{'contig'};
996 if(exists ($_contigs{$contig}{'range'} ) ) {
998 print join ("\t",$chrname, "FPC","contig",
999 $gffcontigs{$contig}{'start'}+$displacement,
1000 $gffcontigs{$contig}{'end'}+$displacement,
1001 ".",".",".",
1002 "contig \"ctg$contig\"; Name \"ctg$contig\"\n");
1005 my @clones = (keys %{$_contigs{$contig}{'clones'}} );
1006 foreach my $clone (@clones) {
1007 if(exists ($_clones{$clone}{'range'}) ) {
1008 print join ("\t",$chrname,"FPC");
1009 my $type = $_clones{$clone}{'type'};
1011 if ($clone =~ /sd1$/) {
1012 $clone =~ s/sd1$//;
1013 $type = "sequenced";
1016 print join ("\t","\t$type",$gffclones{$clone}{'start'}
1017 +$displacement,$gffclones{$clone}{'end'}
1018 +$displacement,".",".",".",
1019 "$type \"$clone\"; Name \"$clone\"");
1021 my @markers = keys %{$_clones{$clone}{'markers'}};
1022 print "; Marker_hit" if (scalar(@markers));
1024 foreach my $mkr(@markers) {
1025 if (exists($_markers{$mkr}{'framework'})) {
1026 print " \"$mkr ",$_markers{$mkr}{'group'}," ",
1027 $_markers{$mkr}{'global'},"\"";
1029 else {
1030 print (" \"$mkr 0 0\"");
1033 print "; Contig_hit \"",$_clones{$clone}{'contig'},"\" "
1034 if (defined($_clones{$clone}{'contig'}));
1036 print "\n";
1039 if (exists ($_contigs{$contig}{'markers'}) ) {
1040 my %list = %{$_contigs{$contig}{'markers'}};
1042 while (my ($k,$v) = each %list) {
1043 print join ("\t",$chrname,"FPC");
1044 my $type = "marker";
1046 $type = "electronicmarker"
1047 if ($_markers{$k}{'type'} eq "eMRK");
1049 if( exists($_markers{$k}{'framework'})) {
1050 $type = "frameworkmarker"
1051 if($_markers{$k}{'framework'} == 1);
1053 $type = "placementmarker"
1054 if($_markers{$k}{'framework'} == 0);
1057 print join ("\t","\t$type",$gffmarkers{$contig}{$k}
1058 + $displacement,$gffmarkers{$contig}{$k}
1059 + $displacement,".",".",".",
1060 "$type \"$k\"; Name \"$k\"");
1062 my @clonelist;
1063 my @clones = keys %{$_markers{$k}{'clones'}};
1065 foreach my $cl (@clones) {
1066 push (@clonelist, $cl)
1067 if($_clones{$cl}{'contig'} == $contig);
1070 $" = " ";
1071 print("; Contig_hit \"ctg$contig - ",
1072 scalar(@clonelist),"\" (@clonelist)\n");
1075 $displacement += $margin + $gffcontigs{$contig}{'end'};
1080 =head2 _calc_markerposition
1082 Title : _calc_markerposition
1083 Usage : $map->_calc_markerposition();
1084 Function: Calculates the position of the marker in the contig
1085 Returns : none
1086 Args : none
1088 =cut
1090 sub _calc_markerposition {
1091 my ($self) = @_;
1092 my %_contigs = %{$self->{'_contigs'}};
1093 my %_markers = %{$self->{'_markers'}};
1094 my %_clones = %{$self->{'_clones'}};
1096 my $i;
1097 my ($depth, $save_depth);
1098 my ($x, $y);
1099 my @stack;
1100 my ($k, $j, $s);
1101 my $pos;
1102 my $contig;
1104 # Calculate the position for the marker in the contig
1106 my @contigs = $self->each_contigid();
1107 my @sortedcontigs = sort {$a <=> $b } @contigs;
1108 my $offset;
1109 my %gffclones;
1110 my %gffcontigs;
1112 foreach my $marker ($self->each_markerid()) {
1113 my (@ctgmarker, @sortedctgmarker);
1115 my @clones = (keys %{$_markers{$marker}{'clones'}})
1116 if (exists ($_markers{$marker}{'clones'} ));
1118 foreach my $clone (@clones) {
1119 my $record;
1120 $record->{contig} = $_clones{$clone}{'contig'};
1121 $record->{start} = $_clones{$clone}{'range'}{'start'};
1122 $record->{end} = $_clones{$clone}{'range'}{'end'};
1123 push @ctgmarker,$record;
1126 # sorting by contig and left position
1127 @sortedctgmarker = sort { $a->{'contig'} <=> $b->{'contig'}
1129 $b->{'start'} <=> $a->{'start'}
1131 $b->{'end'} <=> $a->{'end'}
1132 } @ctgmarker;
1134 my $ctg = -1;
1136 for ($i=0; $i < scalar(@sortedctgmarker); $i++) {
1137 if ($ctg != $sortedctgmarker[$i]->{'contig'}) {
1138 if ($ctg == -1) {
1139 $ctg = $sortedctgmarker[$i]->{'contig'};
1141 else {
1142 if ($depth > $save_depth){
1143 $pos = ($x + $y) >> 1;
1144 $_contigs{$ctg}{'markers'}{$marker} = $pos;
1145 $_markers{$marker}{'posincontig'}{$ctg} = $pos;
1149 $ctg = $sortedctgmarker[$i]->{'contig'};
1150 $x = $sortedctgmarker[$i]->{'start'};
1151 $y = $sortedctgmarker[$i]->{'end'};
1152 $stack[0] = $y;
1154 $pos = ($x + $y) >> 1;
1155 $_contigs{$ctg}{'markers'}{$marker} = $pos;
1156 $_markers{$marker}{'posincontig'}{$ctg} = $pos;
1158 $depth = $save_depth = 1;
1160 elsif ($sortedctgmarker[$i]->{'end'} <= $y) {
1161 $stack[$depth++] = $sortedctgmarker[$i]->{'end'};
1162 # MAX
1163 if ($x < $sortedctgmarker[$i]->{'start'} ) {
1164 $x = $sortedctgmarker[$i]->{'start'};
1166 # MIN
1167 if ($y > $sortedctgmarker[$i]->{'end'}) {
1168 $y = $sortedctgmarker[$i]->{'end'};
1171 else {
1172 if ($depth > $save_depth) {
1173 $save_depth = $depth;
1174 $pos = ($x + $y) >> 1;
1175 $_contigs{$ctg}{'markers'}{$marker} = $pos;
1176 $_markers{$marker}{'posincontig'}{$ctg} = $pos;
1179 $x = $sortedctgmarker[$i]->{'start'};
1180 $y = $sortedctgmarker[$i]->{'end'};
1181 $stack[$depth++] = $y;
1183 for($j=-1, $k=0, $s=0; $s<$depth; $s++) {
1184 if ($stack[$s] <$x) {
1185 $stack[$s] = -1;
1186 $j = $s if ($j == -1);
1188 else {
1189 $k++;
1190 # MIN
1191 $y = $stack[$s] if ($y > $stack[$s]);
1192 if ($stack[$j] == -1) {
1193 $stack[$j] = $stack[$s];
1194 $stack[$s] = -1;
1195 while ($stack[$j] != -1) {$j++;}
1197 else {
1198 $j = $s;
1201 $depth = $k;
1204 if ($depth > $save_depth) {
1205 $pos = ($x + $y) >> 1;
1206 $_contigs{$ctg}{'markers'}{$marker} = $pos;
1207 $_markers{$marker}{'posincontig'}{$ctg} = $pos;
1213 =head2 _calc_contigposition
1215 Title : _calc_contigposition
1216 Usage : $map->_calc_contigposition();
1217 Function: calculates the position of the contig in the group
1218 Returns : none
1219 Args : none
1221 =cut
1223 sub _calc_contigposition{
1224 my ($self) = @_;
1226 my %_contigs = %{$self->{'_contigs'}};
1227 my %_markers = %{$self->{'_markers'}};
1228 my %_clones = %{$self->{'_clones'}};
1230 my @contigs = $self->each_contigid();
1231 my @sortedcontigs = sort {$a <=> $b } @contigs;
1233 foreach my $contig (@sortedcontigs) {
1234 my $position = 0;
1235 my $group;
1237 if (exists($_contigs{$contig}{'group'}) ) {
1239 my %weightedmarkers;
1240 my @mkrs = keys (%{$_contigs{$contig}{'markers'}})
1241 if (exists($_contigs{$contig}{'markers'})) ;
1243 my $chr = $_contigs{$contig}{'group'};
1244 $chr = 0 if ($_contigs{$contig}{'group'} =~ /\?/);
1246 foreach my $mkr (@mkrs) {
1247 if (exists($_markers{$mkr}{'group'})) {
1248 if ( $_markers{$mkr}{'group'} == $chr ) {
1249 my @mkrclones = keys( %{$_markers{$mkr}{'clones'}});
1250 my $clonescount = 0;
1251 foreach my $clone (@mkrclones) {
1252 ++$clonescount
1253 if ($_clones{$clone}{'contig'} == $contig);
1255 $weightedmarkers{$_markers{$mkr}{'global'}} =
1256 $clonescount;
1261 my $weightedctgsum = 0;
1262 my $totalhits = 0;
1264 while (my ($mpos,$hits) = each %weightedmarkers) {
1265 $weightedctgsum += ($mpos * $hits);
1266 $totalhits += $hits;
1269 $position = sprintf("%.2f",$weightedctgsum / $totalhits)
1270 if ($totalhits != 0);
1272 $_contigs{$contig}{'position'} = $position;
1277 =head2 _calc_contiggroup
1279 Title : _calc_contiggroup
1280 Usage : $map->_calc_contiggroup();
1281 Function: calculates the group of the contig
1282 Returns : none
1283 Args : none
1285 =cut
1287 sub _calc_contiggroup {
1288 my ($self) = @_;
1289 my %_contig = %{$self->{'_contigs'}};
1290 my @contigs = $self->each_contigid();
1292 foreach my $ctg (@contigs) {
1293 my $chr = floor($ctg/1000);
1294 $_contig{$ctg}{'group'} = $chr;
1298 =head2 _setI<E<lt>TypeE<gt>>Ref
1300 Title : _set<Type>Ref
1301 Usage : These are used for initializing the reference of the hash in
1302 Bio::MapIO (fpc.pm) to the corresponding hash in Bio::Map
1303 (physical.pm). Should be used only from Bio::MapIO System.
1304 $map->setCloneRef(\%_clones);
1305 $map->setMarkerRef(\%_markers);
1306 $map->setContigRef(\%_contigs);
1307 Function: sets the hash references to the corresponding hashes
1308 Returns : none
1309 Args : reference of the hash.
1311 =cut
1313 sub _setCloneRef {
1314 my ($self, $ref) = @_;
1315 %{$self->{'_clones'}} = %{$ref};
1318 sub _setMarkerRef {
1319 my ($self, $ref) = @_;
1320 %{$self->{'_markers'}} = %{$ref};
1323 sub _setContigRef {
1324 my ($self, $ref) = @_;
1325 %{$self->{'_contigs'}} = %{$ref};