add more STDERR output for merge function.
[cxgn-corelibs.git] / lib / CXGN / Map.pm
blob0a193ed42d3c7d2daec52937ecf869bfce265350
1 package CXGN::Map;
3 =head1 NAME
5 CXGN::Map - classes to get information on SGN mapping information and to add new map and map version data (new_map, store, & map_version functions).
7 =head1 DESCRIPTION
9 This class was originally written to retrieve data on genetic maps in the SGN database. However, map types multiplied and this class was re-written as a factory object producing a map object of the appropriate type - genetic, fish, individual, user, etc. These map objects are defined in the CXGN::Map:: namespace. Previous documentation mentioned the existence of a CXGN::Map::Storable class, however, this never seemed to exist and the new map interface and subclasses have been written as read/write objects.
11 The "new" function has been re-cast to act as a factory object and will produce the right type of Map object given the appropriate parameters, which are defined as follows:
13 parameter map type
14 --------- --------
15 map_id genetic or fish
16 map_version_id genetic or fish
17 user_map_id user_map
18 population_id IL map
19 individual_id indivdual_map
21 Note that much of the functionality of this class has been factored out into a CXGN::LinkageGroup object, which also exists in different incarnations for the different map types.
23 =head1 AUTHORS
25 John Binns <zombieite@gmail.com>, Lukas Mueller (lam87@cornell.edu) and Isaak Y Tecle (iyt2@cornell.edu)
29 =head1 FUNCTIONS
31 This class defines the following functions to be implemented by the subclasses, and keeps the old functions for compatibility (see deprecated functions below).
33 =cut
36 use strict;
38 package CXGN::Map;
40 use CXGN::DB::Connection;
41 use CXGN::Map::Version;
43 use base "CXGN::DB::Object";
45 =head2 new
47 Usage: my $map = CXGN::Map->new($dbh, {map_version_id=>30})
48 Desc: creates a new CXGN::Map object
49 Ret:
50 Args: - a database handle, if possible using
51 CXGN::DB::Connection object
52 - a hashref, containing either a key map_id or a key
53 map_version_id, but not both!
54 Side Effects:
55 Example:
57 =cut
59 sub new {
60 my $class=shift;
61 my($dbh,$map_info)=@_;
62 my $self=$class->SUPER::new($dbh);
63 unless(CXGN::DB::Connection::is_valid_dbh($dbh)){die"Invalid DBH";}
64 ref($map_info) eq 'HASH' or die"Must send in a dbh and hash ref with a map_id key or a map_version_id key";
65 $self->{map_version_id}=$map_info->{map_version_id};
66 $self->{map_id}=$map_info->{map_id};
68 my $map_id_t = $self->{map_id};
69 #print STDERR "map id: $map_id_t from map object\n";
70 if($self->{map_id})
72 if($self->{map_version_id})
74 die"You must only send in a map_id or a map_version_id, not both";
76 my $map_version_id_q=$dbh->prepare("SELECT map_version_id
77 FROM map_version
78 WHERE map_id=?
79 AND current_version='t'"
81 $map_version_id_q->execute($self->{map_id});
82 ($self->{map_version_id})=$map_version_id_q->fetchrow_array();
84 $self->{map_version_id} or return undef;
85 my $general_info_q=$dbh->prepare
87 select
88 map_id,
89 map_version_id,
90 date_loaded,
91 current_version,
92 short_name,
93 long_name,
94 abstract,
95 map_type,
96 population_id,
97 has_IL,
98 has_physical
99 from
100 map_version
101 inner join map using (map_id)
102 where
103 map_version_id=?
105 $general_info_q->execute($self->{map_version_id});
107 $self->{map_id},
108 $self->{map_version_id},
109 $self->{date_loaded},
110 $self->{current_version},
111 $self->{short_name},
112 $self->{long_name},
113 $self->{abstract},
114 $self->{map_type},
115 $self->{population_id},
116 $self->{has_IL},
117 $self->{has_physical}
119 )=$general_info_q->fetchrow_array();
120 if(!$self->{map_version_id}){return undef;}
121 my $linkage_q=$dbh->prepare('SELECT linkage_group.lg_id AS lg_id,linkage_group.map_version_id AS map_version_id,
122 lg_order,lg_name, min(position) AS north_centromere, MAX(position) AS south_centromere
123 FROM linkage_group
124 LEFT JOIN marker_location ON (north_location_id=location_id
125 OR south_location_id=location_id)
126 WHERE linkage_group.map_version_id=?
127 GROUP BY linkage_group.lg_id, linkage_group.map_version_id,
128 lg_order, lg_name order by lg_order');
129 $linkage_q->execute($self->{map_version_id});
130 while(my $linkage_group=$linkage_q->fetchrow_hashref())
132 push(@{$self->{linkage_groups}},$linkage_group);
134 return $self;
137 sub store {
138 my $self = shift;
140 my $map_id = $self->get_map_id();
141 print STDERR "map id from store: $map_id\n";
142 if ($map_id) {
143 my $sth = $self->get_dbh()->prepare("UPDATE sgn.map SET
144 short_name = ?,
145 long_name = ?,
146 abstract = ?,
147 map_type = ?,
148 parent1_stock_id = ?,
149 parent2_stock_id = ?,
150 units = ?,
151 population_stock_id = ?
152 WHERE map_id = ?"
154 $sth->execute($self->{short_name},
155 $self->{long_name},
156 $self->{abstract},
157 $self->{map_type},
158 $self->{parent1_stock_id},
159 $self->{parent2_stock_id},
160 $self->get_units(),
161 $self->{population_stock_id},
162 $map_id
165 print STDERR "Storing map data... \n";
166 print STDERR "updated map id: $map_id\n";
167 #$dbh->last_insert_id("map", "sgn");
168 return $map_id;
170 } else {
171 print STDERR "No map id\n";
172 return 0;
178 sub new_map {
179 my $self=shift;
180 my $dbh = shift;
181 my $name = shift;
182 my ($map_id, $sth);
184 print STDERR "Short map name: $name\n";
185 if ($name) {
186 $sth = $dbh->prepare("SELECT map_id
187 FROM sgn.map
188 WHERE short_name ILIKE ?"
190 $sth->execute($name);
191 $map_id = $sth->fetchrow_array();
192 print STDERR "Map Id: $map_id\n";
194 else {
195 print STDERR "Provide map name, please.\n";
196 die "No map name provided!\n";
199 unless ($map_id) {
200 $sth = $dbh->prepare("INSERT INTO sgn.map (short_name, map_type) VALUES (?, 'genetic')");
201 $sth->execute($name);
202 $map_id = $dbh->last_insert_id("map", "sgn");
203 print STDERR "stored new Map Id: $map_id\n";
206 my ($map, $map_version_id);
207 if ($map_id) {
208 $map_version_id = CXGN::Map::Version->map_version($dbh, $map_id);
209 #$map_version_id= $self->map_version($dbh, $map_id);
210 print STDERR "created map version_id: $map_version_id for map_id: $map_id\n";
211 $map = CXGN::Map->new($dbh, {map_id=>$map_id});
212 my $new_map_id = $map->{map_id};
213 print STDERR "new_map function with map_id = $new_map_id.\n";
218 return $map;
223 =head2 accessors set_short_name, get_short_name
225 Property:
226 Setter Args:
227 Getter Args:
228 Getter Ret:
229 Side Effects:
230 Description:
232 =cut
234 sub get_short_name {
235 my $self=shift;
236 return $self->{short_name};
239 sub set_short_name {
240 my $self=shift;
241 $self->{short_name}=shift;
244 =head2 accessors set_long_name, get_long_name
246 Property:
247 Setter Args:
248 Getter Args:
249 Getter Ret:
250 Side Effects:
251 Description:
253 =cut
255 sub get_long_name {
256 my $self=shift;
257 return $self->{long_name};
260 sub set_long_name {
261 my $self=shift;
262 $self->{long_name}=shift;
265 =head2 accessors set_abstract, get_abstract
267 Property:
268 Setter Args:
269 Getter Args:
270 Getter Ret:
271 Side Effects:
272 Description:
274 =cut
276 sub get_abstract {
277 my $self=shift;
278 return $self->{abstract};
281 sub set_abstract {
282 my $self=shift;
283 $self->{abstract}=shift;
287 =head2 accessors get_parent_1, set_parent_1
289 DEPRECATED
290 Usage:
291 Desc:
292 Property
293 Side Effects:
294 Example:
296 =cut
298 sub get_parent_1 {
299 my $self = shift;
300 return $self->{parent_1};
303 sub set_parent_1 {
304 my $self = shift;
305 $self->{parent_1} = shift;
308 =head2 accessors get_parent1_stock_id, set_parent1_stock_id
310 Usage:
311 Desc: sets the stock id of parent 1 of this map.
312 Property
313 Side Effects:
314 Example:
316 =cut
318 sub get_parent1_stock_id {
319 my $self = shift;
320 return $self->{parent1_stock_id};
323 sub set_parent1_stock_id {
324 my $self = shift;
325 $self->{parent1_stock_id} = shift;
328 =head2 accessors get_parent2_stock_id, set_parent2_stock_id
330 Usage:
331 Desc: sets the stock id of the parent 2 of this map.
332 Property
333 Side Effects:
334 Example:
336 =cut
338 sub get_parent2_stock_id {
339 my $self = shift;
340 return $self->{parent2_stock_id};
343 sub set_parent2_stock_id {
344 my $self = shift;
345 $self->{parent2_stock_id} = shift;
348 =head2 accessors get_population_stock_id, set_population_stock_id
350 Usage:
351 Desc: sets the population id of the map, referencing
352 stock table.
353 Property
354 Side Effects:
355 Example:
357 =cut
359 sub get_population_stock_id {
360 my $self = shift;
361 return $self->{population_stock_id};
364 sub set_population_stock_id {
365 my $self = shift;
366 $self->{population_stock_id} = shift;
369 =head2 accessors get_population_id, set_population_id
371 DEPRECATED.
372 Usage:
373 Desc:
374 Property
375 Side Effects:
376 Example:
378 =cut
380 sub get_population_id {
381 my $self = shift;
382 return $self->{population_id};
385 sub set_population_id {
386 my $self = shift;
387 $self->{population_id} = shift;
390 =head2 get_map_id
392 Usage:
393 Desc:
394 Ret:
395 Args:
396 Side Effects:
397 Example:
399 =cut
402 sub set_map_id {
403 my $self = shift;
404 $self->{map_id}=shift;
406 sub get_map_id {
407 my $self = shift;
408 return $self->{map_id};
412 =head2 accessors set_linkage_groups, get_linkage_groups
414 Property:
415 Setter Args:
416 Getter Args:
417 Getter Ret:
418 Side Effects:
419 Description:
421 =cut
423 sub get_linkage_groups {
424 my $self=shift;
425 return @{$self->{linkage_groups}};
428 sub set_linkage_groups {
429 my $self=shift;
430 @{$self->{linkage_groups}}=@_;
433 =head2 function add_linkage_group
435 Synopsis:
436 Arguments:
437 Returns:
438 Side effects:
439 Description:
441 =cut
443 sub add_linkage_group {
444 my $self = shift;
445 my $lg = shift;
446 push @{$self->{linkage_groups}}, $lg;
450 =head2 accessors set_map_type, get_map_type
452 Property:
453 Setter Args:
454 Getter Args:
455 Getter Ret:
456 Side Effects:
457 Description:
459 =cut
461 sub get_map_type {
462 my $self=shift;
463 return $self->{map_type};
466 sub set_map_type {
467 my $self=shift;
468 $self->{map_type}=shift;
472 =head2 function get_units
474 Synopsis:
475 Arguments:
476 Returns:
477 Side effects:
478 Description:
480 =cut
482 sub get_units {
483 my $self=shift;
484 if ($self->get_map_type() eq "genetic") {
485 return "cM";
487 elsif ($self->get_map_type() eq "fish") {
488 return "%";
490 elsif ($self->get_map_type() =~ /sequenc/) {
491 return "MB";
493 elsif ($self->get_map_type() =~ /qtl/i) {
494 return "cM";
496 else {
497 return "unknown";
506 =head1 DEPRECATED FUNCTIONS
508 These functions are still working but should not be used in new code.
510 Note that these functions only work as getters and not as setters.
512 =cut
514 =head2 function map_id
516 Synopsis:
517 Arguments:
518 Returns:
519 Side effects:
520 Description:
522 =cut
525 sub map_id {
526 my $self=shift;
527 return $self->{map_id};
530 =head2 function map_version_id
532 Synopsis:
533 Arguments:
534 Returns:
535 Side effects:
536 Description:
538 =cut
540 sub map_version_id {
541 my $self=shift;
542 return $self->{map_version_id};
545 =head2 function short_name
547 Synopsis:
548 Arguments:
549 Returns:
550 Side effects:
551 Description:
553 =cut
555 sub short_name {
556 my $self=shift;
557 return $self->{short_name};
560 =head2 function long_name
562 Synopsis:
563 Arguments:
564 Returns:
565 Side effects:
566 Description:
568 =cut
570 sub long_name {
571 my $self=shift;
572 return $self->{long_name};
575 =head2 function abstract
577 Synopsis:
578 Arguments:
579 Returns:
580 Side effects:
581 Description:
583 =cut
585 sub abstract {
586 my $self=shift;
587 return $self->{abstract};
590 =head2 linkage_groups
592 Usage:
593 Desc:
594 Ret: a reference to an array of hashrefs with linkage group info.
595 hash keys include lg_name and lg_order
596 Args:
597 Side Effects:
598 Example:
600 =cut
602 sub linkage_groups {
603 my $self=shift;
604 if($self->{linkage_groups})
606 return $self->{linkage_groups};
608 else
610 return [];
614 =head2 map_type
616 Usage:
617 Desc:
618 Ret: the type of the map, either 'fish' for a fish map
619 or 'genetic' for a genetic map.
620 Args:
621 Side Effects:
622 Example:
624 =cut
626 sub map_type {
627 my $self = shift;
628 return $self->{map_type};
631 =head2 has_IL
633 Usage:
634 Desc:
635 Ret:
636 Args:
637 Side Effects:
638 Example:
640 =cut
642 sub has_IL {
643 my $self = shift;
644 return $self->{has_IL};
647 =head2 has_physical
649 Usage:
650 Desc:
651 Ret:
652 Args:
653 Side Effects:
654 Example:
656 =cut
658 sub has_physical {
659 my $self = shift;
660 return $self->{has_physical};
666 =head2 get_chr_names
668 Usage:
669 Desc: a shortcut function to get at the chromosome names,
670 sorted by lg_order
671 Ret: a list of chromosome names.
672 Args:
673 Side Effects:
674 Example:
676 =cut
678 sub get_chr_names {
679 my $self = shift;
680 my $linkage_groups_ref = $self->linkage_groups();
681 my @names = map $_->{lg_name}, @{$linkage_groups_ref};
682 return @names;
685 =head2 has_linkage_group
687 Usage:
688 Desc:
689 Ret: 1 if the string or number represents a linkage group
690 of this map
691 0 if it doesn\'t
692 Args: a string or number describing a possible linkage
693 group of this map
694 Side Effects:
695 Example:
697 =cut
699 sub has_linkage_group {
700 my $self = shift;
701 my $candidate = shift;
702 chomp($candidate);
703 $candidate=~ s/\s*(.*)\s*/$1/;
704 foreach my $n (map $_->{lg_name} , @{$self->linkage_groups()}) {
705 #print STDERR "comparing $n with $candidate...\n";
706 if ($candidate =~ /^$n$/i) {
707 #print STDERR "Yip!\n";
708 return 1;
711 return 0;
714 =head2 function get_centromere
716 Synopsis: my ($north, $south, $center) = $map->get_centromere($lg_name)
717 Arguments: a valid linkage group name
718 Returns: a three member list, the first element corresponds
719 to the north boundary of the centromere in cM
720 the second corresponds to the south boundary of
721 the centromere in cM, the third is the arithmetic mean
722 of the two first values.
723 Side effects: none
724 Description:
726 =cut
728 sub get_centromere {
729 my $self=shift;
730 my $lg = shift;
732 if (! $self->has_linkage_group($lg)) {
733 die "Not a valid linkage group for this map!\n";
736 my $lg_hash = $self->get_linkage_group_hash($lg);
737 # foreach my $k (keys %$lg_hash) {
738 # print " $k, $lg_hash->{$k}\n";
740 my $north = $lg_hash->{north_centromere} || 0;
741 my $south = $lg_hash->{south_centromere} || 0;
742 return ($north, $south, int(($north+$south)/2));
745 sub get_linkage_group_hash {
746 my $self= shift;
747 my $lg_name = shift;
748 foreach my $lg_hash (@{$self->linkage_groups()}) {
749 if ($lg_hash->{lg_name} eq $lg_name) {
750 return $lg_hash;