changing over to stock tables (from accession)
[cxgn-corelibs.git] / lib / CXGN / Map.pm
blobc744da8de7df0242f6a49c886c947e899ec0b53d
2 =head1 NAME
4 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).
6 =head1 DESCRIPTION
8 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.
10 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:
12 parameter map type
13 --------- --------
14 map_id genetic or fish
15 map_version_id genetic or fish
16 user_map_id user_map
17 population_id IL map
18 individual_id indivdual_map
20 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.
22 =head1 AUTHORS
24 John Binns <zombieite@gmail.com>, Lukas Mueller (lam87@cornell.edu) and Isaak Y Tecle (iyt2@cornell.edu)
28 =head1 FUNCTIONS
30 This class defines the following functions to be implemented by the subclasses, and keeps the old functions for compatibility (see deprecated functions below).
32 =cut
34 use strict;
35 use CXGN::DB::Connection;
36 use CXGN::Map::Version;
37 package CXGN::Map;
39 =head2 new
41 Usage: my $map = CXGN::Map->new($dbh, {map_version_id=>30})
42 Desc: creates a new CXGN::Map object
43 Ret:
44 Args: - a database handle, if possible using
45 CXGN::DB::Connection object
46 - a hashref, containing either a key map_id or a key
47 map_version_id, but not both!
48 Side Effects:
49 Example:
51 =cut
53 sub new {
54 my $class=shift;
55 my($dbh,$map_info)=@_;
56 my $self=bless({},$class);
57 unless(CXGN::DB::Connection::is_valid_dbh($dbh)){die"Invalid DBH";}
58 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";
59 $self->{map_version_id}=$map_info->{map_version_id};
60 $self->{map_id}=$map_info->{map_id};
62 my $map_id_t = $self->{map_id};
63 #print STDERR "map id: $map_id_t from map object\n";
64 if($self->{map_id})
66 if($self->{map_version_id})
68 die"You must only send in a map_id or a map_version_id, not both";
70 my $map_version_id_q=$dbh->prepare("SELECT map_version_id
71 FROM map_version
72 WHERE map_id=?
73 AND current_version='t'"
75 $map_version_id_q->execute($self->{map_id});
76 ($self->{map_version_id})=$map_version_id_q->fetchrow_array();
78 $self->{map_version_id} or return undef;
79 my $general_info_q=$dbh->prepare
81 select
82 map_id,
83 map_version_id,
84 date_loaded,
85 current_version,
86 short_name,
87 long_name,
88 abstract,
89 map_type,
90 population_id,
91 has_IL,
92 has_physical
93 from
94 map_version
95 inner join map using (map_id)
96 where
97 map_version_id=?
98 ');
99 $general_info_q->execute($self->{map_version_id});
101 $self->{map_id},
102 $self->{map_version_id},
103 $self->{date_loaded},
104 $self->{current_version},
105 $self->{short_name},
106 $self->{long_name},
107 $self->{abstract},
108 $self->{map_type},
109 $self->{population_id},
110 $self->{has_IL},
111 $self->{has_physical}
113 )=$general_info_q->fetchrow_array();
114 if(!$self->{map_version_id}){return undef;}
115 my $linkage_q=$dbh->prepare('SELECT linkage_group.lg_id AS lg_id,linkage_group.map_version_id AS map_version_id,
116 lg_order,lg_name, min(position) AS north_centromere, MAX(position) AS south_centromere
117 FROM linkage_group
118 LEFT JOIN marker_location ON (north_location_id=location_id
119 OR south_location_id=location_id)
120 WHERE linkage_group.map_version_id=?
121 GROUP BY linkage_group.lg_id, linkage_group.map_version_id,
122 lg_order, lg_name order by lg_order');
123 $linkage_q->execute($self->{map_version_id});
124 while(my $linkage_group=$linkage_q->fetchrow_hashref())
126 push(@{$self->{linkage_groups}},$linkage_group);
128 return $self;
131 sub store {
132 my $self = shift;
133 my $dbh = CXGN::DB::Connection->new();
134 my $map_id = $self->get_map_id();
135 print STDERR "map id from store: $map_id\n";
136 if ($map_id) {
137 my $sth = $dbh->prepare("UPDATE sgn.map SET
138 short_name = ?,
139 long_name = ?,
140 abstract = ?,
141 map_type = ?,
142 parent1_stock_id = ?,
143 parent2_stock_id = ?,
144 units = ?,
145 population_stock_id = ?
146 WHERE map_id = ?"
148 $sth->execute($self->{short_name},
149 $self->{long_name},
150 $self->{abstract},
151 $self->{map_type},
152 $self->{parent1_stock_id},
153 $self->{parent2_stock_id},
154 $self->get_units(),
155 $self->{population_stock_id},
156 $map_id
159 print STDERR "Storing map data... \n";
160 print STDERR "updated map id: $map_id\n";
161 #$dbh->last_insert_id("map", "sgn");
162 return $map_id;
164 } else {
165 print STDERR "No map id\n";
166 return 0;
172 sub new_map {
173 my $self=shift;
174 my $dbh = shift;
175 my $name = shift;
176 my ($map_id, $sth);
178 print STDERR "Short map name: $name\n";
179 if ($name) {
180 $sth = $dbh->prepare("SELECT map_id
181 FROM sgn.map
182 WHERE short_name ILIKE ?"
184 $sth->execute($name);
185 $map_id = $sth->fetchrow_array();
186 print STDERR "Map Id: $map_id\n";
188 else {
189 print STDERR "Provide map name, please.\n";
190 die "No map name provided!\n";
193 unless ($map_id) {
194 $sth = $dbh->prepare("INSERT INTO sgn.map (short_name) VALUES (?)");
195 $sth->execute($name);
196 $map_id = $dbh->last_insert_id("map", "sgn");
197 print STDERR "stored new Map Id: $map_id\n";
200 my ($map, $map_version_id);
201 if ($map_id) {
202 $map_version_id = CXGN::Map::Version->map_version($dbh, $map_id);
203 #$map_version_id= $self->map_version($dbh, $map_id);
204 print STDERR "created map version_id: $map_version_id for map_id: $map_id\n";
205 $map = CXGN::Map->new($dbh, {map_id=>$map_id});
206 my $new_map_id = $map->{map_id};
207 print STDERR "new_map function with map_id = $new_map_id.\n";
212 return $map;
217 =head2 accessors set_short_name, get_short_name
219 Property:
220 Setter Args:
221 Getter Args:
222 Getter Ret:
223 Side Effects:
224 Description:
226 =cut
228 sub get_short_name {
229 my $self=shift;
230 return $self->{short_name};
233 sub set_short_name {
234 my $self=shift;
235 $self->{short_name}=shift;
238 =head2 accessors set_long_name, get_long_name
240 Property:
241 Setter Args:
242 Getter Args:
243 Getter Ret:
244 Side Effects:
245 Description:
247 =cut
249 sub get_long_name {
250 my $self=shift;
251 return $self->{long_name};
254 sub set_long_name {
255 my $self=shift;
256 $self->{long_name}=shift;
259 =head2 accessors set_abstract, get_abstract
261 Property:
262 Setter Args:
263 Getter Args:
264 Getter Ret:
265 Side Effects:
266 Description:
268 =cut
270 sub get_abstract {
271 my $self=shift;
272 return $self->{abstract};
275 sub set_abstract {
276 my $self=shift;
277 $self->{abstract}=shift;
281 =head2 accessors get_parent_1, set_parent_1
283 DEPRECATED
284 Usage:
285 Desc:
286 Property
287 Side Effects:
288 Example:
290 =cut
292 sub get_parent_1 {
293 my $self = shift;
294 return $self->{parent_1};
297 sub set_parent_1 {
298 my $self = shift;
299 $self->{parent_1} = shift;
302 =head2 accessors get_parent1_stock_id, set_parent1_stock_id
304 Usage:
305 Desc: sets the stock id of parent 1 of this map.
306 Property
307 Side Effects:
308 Example:
310 =cut
312 sub get_parent1_stock_id {
313 my $self = shift;
314 return $self->{parent1_stock_id};
317 sub set_parent1_stock_id {
318 my $self = shift;
319 $self->{parent1_stock_id} = shift;
322 =head2 accessors get_parent2_stock_id, set_parent2_stock_id
324 Usage:
325 Desc: sets the stock id of the parent 2 of this map.
326 Property
327 Side Effects:
328 Example:
330 =cut
332 sub get_parent2_stock_id {
333 my $self = shift;
334 return $self->{parent2_stock_id};
337 sub set_parent2_stock_id {
338 my $self = shift;
339 $self->{parent2_stock_id} = shift;
342 =head2 accessors get_population_stock_id, set_population_stock_id
344 Usage:
345 Desc: sets the population id of the map, referencing
346 stock table.
347 Property
348 Side Effects:
349 Example:
351 =cut
353 sub get_population_stock_id {
354 my $self = shift;
355 return $self->{population_stock_id};
358 sub set_population_stock_id {
359 my $self = shift;
360 $self->{population_stock_id} = shift;
363 =head2 accessors get_population_id, set_population_id
365 DEPRECATED.
366 Usage:
367 Desc:
368 Property
369 Side Effects:
370 Example:
372 =cut
374 sub get_population_id {
375 my $self = shift;
376 return $self->{population_id};
379 sub set_population_id {
380 my $self = shift;
381 $self->{population_id} = shift;
384 =head2 get_map_id
386 Usage:
387 Desc:
388 Ret:
389 Args:
390 Side Effects:
391 Example:
393 =cut
396 sub set_map_id {
397 my $self = shift;
398 $self->{map_id}=shift;
400 sub get_map_id {
401 my $self = shift;
402 return $self->{map_id};
406 =head2 accessors set_linkage_groups, get_linkage_groups
408 Property:
409 Setter Args:
410 Getter Args:
411 Getter Ret:
412 Side Effects:
413 Description:
415 =cut
417 sub get_linkage_groups {
418 my $self=shift;
419 return @{$self->{linkage_groups}};
422 sub set_linkage_groups {
423 my $self=shift;
424 @{$self->{linkage_groups}}=@_;
427 =head2 function add_linkage_group
429 Synopsis:
430 Arguments:
431 Returns:
432 Side effects:
433 Description:
435 =cut
437 sub add_linkage_group {
438 my $self = shift;
439 my $lg = shift;
440 push @{$self->{linkage_groups}}, $lg;
444 =head2 accessors set_map_type, get_map_type
446 Property:
447 Setter Args:
448 Getter Args:
449 Getter Ret:
450 Side Effects:
451 Description:
453 =cut
455 sub get_map_type {
456 my $self=shift;
457 return $self->{map_type};
460 sub set_map_type {
461 my $self=shift;
462 $self->{map_type}=shift;
466 =head2 function get_units
468 Synopsis:
469 Arguments:
470 Returns:
471 Side effects:
472 Description:
474 =cut
476 sub get_units {
477 my $self=shift;
478 if ($self->get_map_type() eq "genetic") {
479 return "cM";
481 elsif ($self->get_map_type() eq "fish") {
482 return "%";
484 elsif ($self->get_map_type() =~ /sequenc/) {
485 return "MB";
487 elsif ($self->get_map_type() =~ /qtl/i) {
488 return "cM";
490 else {
491 return "unknown";
500 =head1 DEPRECATED FUNCTIONS
502 These functions are still working but should not be used in new code.
504 Note that these functions only work as getters and not as setters.
506 =cut
508 =head2 function map_id
510 Synopsis:
511 Arguments:
512 Returns:
513 Side effects:
514 Description:
516 =cut
519 sub map_id {
520 my $self=shift;
521 return $self->{map_id};
524 =head2 function map_version_id
526 Synopsis:
527 Arguments:
528 Returns:
529 Side effects:
530 Description:
532 =cut
534 sub map_version_id {
535 my $self=shift;
536 return $self->{map_version_id};
539 =head2 function short_name
541 Synopsis:
542 Arguments:
543 Returns:
544 Side effects:
545 Description:
547 =cut
549 sub short_name {
550 my $self=shift;
551 return $self->{short_name};
554 =head2 function long_name
556 Synopsis:
557 Arguments:
558 Returns:
559 Side effects:
560 Description:
562 =cut
564 sub long_name {
565 my $self=shift;
566 return $self->{long_name};
569 =head2 function abstract
571 Synopsis:
572 Arguments:
573 Returns:
574 Side effects:
575 Description:
577 =cut
579 sub abstract {
580 my $self=shift;
581 return $self->{abstract};
584 =head2 linkage_groups
586 Usage:
587 Desc:
588 Ret: a reference to an array of hashrefs with linkage group info.
589 hash keys include lg_name and lg_order
590 Args:
591 Side Effects:
592 Example:
594 =cut
596 sub linkage_groups {
597 my $self=shift;
598 if($self->{linkage_groups})
600 return $self->{linkage_groups};
602 else
604 return [];
608 =head2 map_type
610 Usage:
611 Desc:
612 Ret: the type of the map, either 'fish' for a fish map
613 or 'genetic' for a genetic map.
614 Args:
615 Side Effects:
616 Example:
618 =cut
620 sub map_type {
621 my $self = shift;
622 return $self->{map_type};
625 =head2 has_IL
627 Usage:
628 Desc:
629 Ret:
630 Args:
631 Side Effects:
632 Example:
634 =cut
636 sub has_IL {
637 my $self = shift;
638 return $self->{has_IL};
641 =head2 has_physical
643 Usage:
644 Desc:
645 Ret:
646 Args:
647 Side Effects:
648 Example:
650 =cut
652 sub has_physical {
653 my $self = shift;
654 return $self->{has_physical};
660 =head2 get_chr_names
662 Usage:
663 Desc: a shortcut function to get at the chromosome names,
664 sorted by lg_order
665 Ret: a list of chromosome names.
666 Args:
667 Side Effects:
668 Example:
670 =cut
672 sub get_chr_names {
673 my $self = shift;
674 my $linkage_groups_ref = $self->linkage_groups();
675 my @names = map $_->{lg_name}, @{$linkage_groups_ref};
676 return @names;
679 =head2 has_linkage_group
681 Usage:
682 Desc:
683 Ret: 1 if the string or number represents a linkage group
684 of this map
685 0 if it doesn\'t
686 Args: a string or number describing a possible linkage
687 group of this map
688 Side Effects:
689 Example:
691 =cut
693 sub has_linkage_group {
694 my $self = shift;
695 my $candidate = shift;
696 chomp($candidate);
697 $candidate=~ s/\s*(.*)\s*/$1/;
698 foreach my $n (map $_->{lg_name} , @{$self->linkage_groups()}) {
699 #print STDERR "comparing $n with $candidate...\n";
700 if ($candidate =~ /^$n$/i) {
701 #print STDERR "Yip!\n";
702 return 1;
705 return 0;
708 =head2 function get_centromere
710 Synopsis: my ($north, $south, $center) = $map->get_centromere($lg_name)
711 Arguments: a valid linkage group name
712 Returns: a three member list, the first element corresponds
713 to the north boundary of the centromere in cM
714 the second corresponds to the south boundary of
715 the centromere in cM, the third is the arithmetic mean
716 of the two first values.
717 Side effects: none
718 Description:
720 =cut
722 sub get_centromere {
723 my $self=shift;
724 my $lg = shift;
726 if (! $self->has_linkage_group($lg)) {
727 die "Not a valid linkage group for this map!\n";
730 my $lg_hash = $self->get_linkage_group_hash($lg);
731 # foreach my $k (keys %$lg_hash) {
732 # print " $k, $lg_hash->{$k}\n";
734 my $north = $lg_hash->{north_centromere};
735 my $south = $lg_hash->{south_centromere};
736 return ($north, $south, int(($north+$south)/2));
739 sub get_linkage_group_hash {
740 my $self= shift;
741 my $lg_name = shift;
742 foreach my $lg_hash (@{$self->linkage_groups()}) {
743 if ($lg_hash->{lg_name} eq $lg_name) {
744 return $lg_hash;
750 return 1;