PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/CXGN/Map.pm

https://github.com/solgenomics/cxgn-corelibs
Perl | 764 lines | 583 code | 173 blank | 8 comment | 30 complexity | 57db738838c74b950547af81d7ded72a MD5 | raw file
  1. package CXGN::Map;
  2. =head1 NAME
  3. 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).
  4. =head1 DESCRIPTION
  5. 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.
  6. 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:
  7. parameter map type
  8. --------- --------
  9. map_id genetic or fish
  10. map_version_id genetic or fish
  11. user_map_id user_map
  12. population_id IL map
  13. individual_id indivdual_map
  14. 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.
  15. =head1 AUTHORS
  16. John Binns <zombieite@gmail.com>, Lukas Mueller (lam87@cornell.edu) and Isaak Y Tecle (iyt2@cornell.edu)
  17. =head1 FUNCTIONS
  18. This class defines the following functions to be implemented by the subclasses, and keeps the old functions for compatibility (see deprecated functions below).
  19. =cut
  20. use strict;
  21. use warnings;
  22. package CXGN::Map;
  23. use CXGN::DB::Connection;
  24. use CXGN::Map::Version;
  25. use base "CXGN::DB::Object";
  26. =head2 new
  27. Usage: my $map = CXGN::Map->new($dbh, {map_version_id=>30})
  28. Desc: creates a new CXGN::Map object
  29. Ret:
  30. Args: - a database handle, if possible using
  31. CXGN::DB::Connection object
  32. - a hashref, containing either a key map_id or a key
  33. map_version_id, but not both!
  34. Side Effects:
  35. Example:
  36. =cut
  37. sub new {
  38. my $class=shift;
  39. my($dbh,$map_info)=@_;
  40. my $self=$class->SUPER::new($dbh);
  41. unless(CXGN::DB::Connection::is_valid_dbh($dbh)){die"Invalid DBH";}
  42. 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";
  43. $self->{map_version_id}=$map_info->{map_version_id};
  44. $self->{map_id}=$map_info->{map_id};
  45. my $map_id_t = $self->{map_id};
  46. #print STDERR "map id: $map_id_t from map object\n";
  47. if($self->{map_id})
  48. {
  49. if($self->{map_version_id})
  50. {
  51. die"You must only send in a map_id or a map_version_id, not both";
  52. }
  53. my $map_version_id_q=$dbh->prepare("SELECT map_version_id
  54. FROM map_version
  55. WHERE map_id=?
  56. AND current_version='t'"
  57. );
  58. $map_version_id_q->execute($self->{map_id});
  59. if (my @row = $map_version_id_q->fetchrow_array()) {
  60. $self->{map_version_id} = $row[0];
  61. } else {
  62. print STDERR "ERROR no map_version_id\n";
  63. }
  64. }
  65. $self->{map_version_id} or return undef;
  66. my $general_info_q=$dbh->prepare
  67. ('
  68. select
  69. map_id,
  70. map_version_id,
  71. date_loaded,
  72. current_version,
  73. short_name,
  74. long_name,
  75. abstract,
  76. map_type,
  77. population_id,
  78. has_IL,
  79. has_physical
  80. from
  81. map_version
  82. inner join map using (map_id)
  83. where
  84. map_version_id=?
  85. ');
  86. $general_info_q->execute($self->{map_version_id});
  87. (
  88. $self->{map_id},
  89. $self->{map_version_id},
  90. $self->{date_loaded},
  91. $self->{current_version},
  92. $self->{short_name},
  93. $self->{long_name},
  94. $self->{abstract},
  95. $self->{map_type},
  96. $self->{population_id},
  97. $self->{has_IL},
  98. $self->{has_physical}
  99. )=$general_info_q->fetchrow_array();
  100. if(!$self->{map_version_id}){return undef;}
  101. my $linkage_q=$dbh->prepare('SELECT linkage_group.lg_id AS lg_id,linkage_group.map_version_id AS map_version_id,
  102. lg_order,lg_name, min(position) AS north_centromere, MAX(position) AS south_centromere
  103. FROM linkage_group
  104. LEFT JOIN marker_location ON (north_location_id=location_id
  105. OR south_location_id=location_id)
  106. WHERE linkage_group.map_version_id=?
  107. GROUP BY linkage_group.lg_id, linkage_group.map_version_id,
  108. lg_order, lg_name order by lg_order');
  109. $linkage_q->execute($self->{map_version_id});
  110. while(my $linkage_group=$linkage_q->fetchrow_hashref())
  111. {
  112. push(@{$self->{linkage_groups}},$linkage_group);
  113. }
  114. return $self;
  115. }
  116. sub store {
  117. my $self = shift;
  118. my $map_id = $self->get_map_id();
  119. print STDERR "map id from store: $map_id\n";
  120. if ($map_id) {
  121. my $sth = $self->get_dbh()->prepare("UPDATE sgn.map SET
  122. short_name = ?,
  123. long_name = ?,
  124. abstract = ?,
  125. map_type = ?,
  126. parent1_stock_id = ?,
  127. parent2_stock_id = ?,
  128. units = ?,
  129. population_stock_id = ?
  130. WHERE map_id = ?"
  131. );
  132. $sth->execute($self->{short_name},
  133. $self->{long_name},
  134. $self->{abstract},
  135. $self->{map_type},
  136. $self->{parent1_stock_id},
  137. $self->{parent2_stock_id},
  138. $self->get_units(),
  139. $self->{population_stock_id},
  140. $map_id
  141. );
  142. print STDERR "Storing map data... \n";
  143. print STDERR "updated map id: $map_id\n";
  144. #$dbh->last_insert_id("map", "sgn");
  145. return $map_id;
  146. } else {
  147. print STDERR "No map id\n";
  148. return 0;
  149. }
  150. }
  151. sub new_map {
  152. my $self=shift;
  153. my $dbh = shift;
  154. my $name = shift;
  155. my ($map_id, $sth);
  156. print STDERR "Short map name: $name\n";
  157. if ($name) {
  158. $sth = $dbh->prepare("SELECT map_id
  159. FROM sgn.map
  160. WHERE short_name ILIKE ?"
  161. );
  162. $sth->execute($name);
  163. if (my @row = $sth->fetchrow_array) {
  164. $map_id = $row[0];
  165. } else {
  166. print STDERR "Error: No Map Id for $name\n";
  167. }
  168. }
  169. else {
  170. print STDERR "Provide map name, please.\n";
  171. die "No map name provided!\n";
  172. }
  173. unless ($map_id) {
  174. $sth = $dbh->prepare("INSERT INTO sgn.map (short_name, map_type) VALUES (?, 'genetic') RETURNING map_id");
  175. $sth->execute($name) or die "ERROR can not create map\n";;
  176. ($map_id) = $sth->fetchrow_array() or die "ERROR inserting map\n";
  177. print STDERR "stored new Map Id: $map_id\n";
  178. }
  179. my ($map, $map_version_id);
  180. if ($map_id) {
  181. $map_version_id = CXGN::Map::Version->map_version($dbh, $map_id);
  182. #$map_version_id= $self->map_version($dbh, $map_id);
  183. print STDERR "created map version_id: $map_version_id for map_id: $map_id\n";
  184. $map = CXGN::Map->new($dbh, {map_id=>$map_id});
  185. my $new_map_id = $map->{map_id};
  186. print STDERR "new_map function with map_id = $new_map_id.\n";
  187. }
  188. return $map;
  189. }
  190. =head2 accessors set_short_name, get_short_name
  191. Property:
  192. Setter Args:
  193. Getter Args:
  194. Getter Ret:
  195. Side Effects:
  196. Description:
  197. =cut
  198. sub get_short_name {
  199. my $self=shift;
  200. return $self->{short_name};
  201. }
  202. sub set_short_name {
  203. my $self=shift;
  204. $self->{short_name}=shift;
  205. }
  206. =head2 accessors set_long_name, get_long_name
  207. Property:
  208. Setter Args:
  209. Getter Args:
  210. Getter Ret:
  211. Side Effects:
  212. Description:
  213. =cut
  214. sub get_long_name {
  215. my $self=shift;
  216. return $self->{long_name};
  217. }
  218. sub set_long_name {
  219. my $self=shift;
  220. $self->{long_name}=shift;
  221. }
  222. =head2 accessors set_abstract, get_abstract
  223. Property:
  224. Setter Args:
  225. Getter Args:
  226. Getter Ret:
  227. Side Effects:
  228. Description:
  229. =cut
  230. sub get_abstract {
  231. my $self=shift;
  232. return $self->{abstract};
  233. }
  234. sub set_abstract {
  235. my $self=shift;
  236. $self->{abstract}=shift;
  237. }
  238. =head2 accessors get_parent_1, set_parent_1
  239. DEPRECATED
  240. Usage:
  241. Desc:
  242. Property
  243. Side Effects:
  244. Example:
  245. =cut
  246. sub get_parent_1 {
  247. my $self = shift;
  248. return $self->{parent_1};
  249. }
  250. sub set_parent_1 {
  251. my $self = shift;
  252. $self->{parent_1} = shift;
  253. }
  254. =head2 accessors get_parent1_stock_id, set_parent1_stock_id
  255. Usage:
  256. Desc: sets the stock id of parent 1 of this map.
  257. Property
  258. Side Effects:
  259. Example:
  260. =cut
  261. sub get_parent1_stock_id {
  262. my $self = shift;
  263. return $self->{parent1_stock_id};
  264. }
  265. sub set_parent1_stock_id {
  266. my $self = shift;
  267. $self->{parent1_stock_id} = shift;
  268. }
  269. =head2 accessors get_parent2_stock_id, set_parent2_stock_id
  270. Usage:
  271. Desc: sets the stock id of the parent 2 of this map.
  272. Property
  273. Side Effects:
  274. Example:
  275. =cut
  276. sub get_parent2_stock_id {
  277. my $self = shift;
  278. return $self->{parent2_stock_id};
  279. }
  280. sub set_parent2_stock_id {
  281. my $self = shift;
  282. $self->{parent2_stock_id} = shift;
  283. }
  284. =head2 accessors get_population_stock_id, set_population_stock_id
  285. Usage:
  286. Desc: sets the population id of the map, referencing
  287. stock table.
  288. Property
  289. Side Effects:
  290. Example:
  291. =cut
  292. sub get_population_stock_id {
  293. my $self = shift;
  294. return $self->{population_stock_id};
  295. }
  296. sub set_population_stock_id {
  297. my $self = shift;
  298. $self->{population_stock_id} = shift;
  299. }
  300. =head2 accessors get_population_id, set_population_id
  301. DEPRECATED.
  302. Usage:
  303. Desc:
  304. Property
  305. Side Effects:
  306. Example:
  307. =cut
  308. sub get_population_id {
  309. my $self = shift;
  310. return $self->{population_id};
  311. }
  312. sub set_population_id {
  313. my $self = shift;
  314. $self->{population_id} = shift;
  315. }
  316. =head2 get_map_id
  317. Usage:
  318. Desc:
  319. Ret:
  320. Args:
  321. Side Effects:
  322. Example:
  323. =cut
  324. sub set_map_id {
  325. my $self = shift;
  326. $self->{map_id}=shift;
  327. }
  328. sub get_map_id {
  329. my $self = shift;
  330. return $self->{map_id};
  331. }
  332. =head2 accessors set_linkage_groups, get_linkage_groups
  333. Property:
  334. Setter Args:
  335. Getter Args:
  336. Getter Ret:
  337. Side Effects:
  338. Description:
  339. =cut
  340. sub get_linkage_groups {
  341. my $self=shift;
  342. return @{$self->{linkage_groups}};
  343. }
  344. sub set_linkage_groups {
  345. my $self=shift;
  346. @{$self->{linkage_groups}}=@_;
  347. }
  348. =head2 function add_linkage_group
  349. Synopsis:
  350. Arguments:
  351. Returns:
  352. Side effects:
  353. Description:
  354. =cut
  355. sub add_linkage_group {
  356. my $self = shift;
  357. my $lg = shift;
  358. push @{$self->{linkage_groups}}, $lg;
  359. }
  360. =head2 accessors set_map_type, get_map_type
  361. Property:
  362. Setter Args:
  363. Getter Args:
  364. Getter Ret:
  365. Side Effects:
  366. Description:
  367. =cut
  368. sub get_map_type {
  369. my $self=shift;
  370. return $self->{map_type};
  371. }
  372. sub set_map_type {
  373. my $self=shift;
  374. $self->{map_type}=shift;
  375. }
  376. =head2 function get_units
  377. Synopsis:
  378. Arguments:
  379. Returns:
  380. Side effects:
  381. Description:
  382. =cut
  383. sub get_units {
  384. my $self=shift;
  385. if ($self->get_map_type() eq "genetic") {
  386. return "cM";
  387. }
  388. elsif ($self->get_map_type() eq "fish") {
  389. return "%";
  390. }
  391. elsif ($self->get_map_type() =~ /sequenc/) {
  392. return "MB";
  393. }
  394. elsif ($self->get_map_type() =~ /qtl/i) {
  395. return "cM";
  396. }
  397. else {
  398. return "unknown";
  399. }
  400. }
  401. =head1 DEPRECATED FUNCTIONS
  402. These functions are still working but should not be used in new code.
  403. Note that these functions only work as getters and not as setters.
  404. =cut
  405. =head2 function map_id
  406. Synopsis:
  407. Arguments:
  408. Returns:
  409. Side effects:
  410. Description:
  411. =cut
  412. sub map_id {
  413. my $self=shift;
  414. return $self->{map_id};
  415. }
  416. =head2 function map_version_id
  417. Synopsis:
  418. Arguments:
  419. Returns:
  420. Side effects:
  421. Description:
  422. =cut
  423. sub map_version_id {
  424. my $self=shift;
  425. return $self->{map_version_id};
  426. }
  427. =head2 function short_name
  428. Synopsis:
  429. Arguments:
  430. Returns:
  431. Side effects:
  432. Description:
  433. =cut
  434. sub short_name {
  435. my $self=shift;
  436. return $self->{short_name};
  437. }
  438. =head2 function long_name
  439. Synopsis:
  440. Arguments:
  441. Returns:
  442. Side effects:
  443. Description:
  444. =cut
  445. sub long_name {
  446. my $self=shift;
  447. return $self->{long_name};
  448. }
  449. =head2 function abstract
  450. Synopsis:
  451. Arguments:
  452. Returns:
  453. Side effects:
  454. Description:
  455. =cut
  456. sub abstract {
  457. my $self=shift;
  458. return $self->{abstract};
  459. }
  460. =head2 linkage_groups
  461. Usage:
  462. Desc:
  463. Ret: a reference to an array of hashrefs with linkage group info.
  464. hash keys include lg_name and lg_order
  465. Args:
  466. Side Effects:
  467. Example:
  468. =cut
  469. sub linkage_groups {
  470. my $self=shift;
  471. if($self->{linkage_groups})
  472. {
  473. return $self->{linkage_groups};
  474. }
  475. else
  476. {
  477. return [];
  478. }
  479. }
  480. =head2 map_type
  481. Usage:
  482. Desc:
  483. Ret: the type of the map, either 'fish' for a fish map
  484. or 'genetic' for a genetic map.
  485. Args:
  486. Side Effects:
  487. Example:
  488. =cut
  489. sub map_type {
  490. my $self = shift;
  491. return $self->{map_type};
  492. }
  493. =head2 has_IL
  494. Usage:
  495. Desc:
  496. Ret:
  497. Args:
  498. Side Effects:
  499. Example:
  500. =cut
  501. sub has_IL {
  502. my $self = shift;
  503. return $self->{has_IL};
  504. }
  505. =head2 has_physical
  506. Usage:
  507. Desc:
  508. Ret:
  509. Args:
  510. Side Effects:
  511. Example:
  512. =cut
  513. sub has_physical {
  514. my $self = shift;
  515. return $self->{has_physical};
  516. }
  517. =head2 get_chr_names
  518. Usage:
  519. Desc: a shortcut function to get at the chromosome names,
  520. sorted by lg_order
  521. Ret: a list of chromosome names.
  522. Args:
  523. Side Effects:
  524. Example:
  525. =cut
  526. sub get_chr_names {
  527. my $self = shift;
  528. my $linkage_groups_ref = $self->linkage_groups();
  529. my @names = map $_->{lg_name}, @{$linkage_groups_ref};
  530. return @names;
  531. }
  532. =head2 has_linkage_group
  533. Usage:
  534. Desc:
  535. Ret: 1 if the string or number represents a linkage group
  536. of this map
  537. 0 if it doesn\'t
  538. Args: a string or number describing a possible linkage
  539. group of this map
  540. Side Effects:
  541. Example:
  542. =cut
  543. sub has_linkage_group {
  544. my $self = shift;
  545. my $candidate = shift;
  546. chomp($candidate);
  547. $candidate=~ s/\s*(.*)\s*/$1/;
  548. foreach my $n (map $_->{lg_name} , @{$self->linkage_groups()}) {
  549. #print STDERR "comparing $n with $candidate...\n";
  550. if ($candidate =~ /^$n$/i) {
  551. #print STDERR "Yip!\n";
  552. return 1;
  553. }
  554. }
  555. return 0;
  556. }
  557. =head2 function get_centromere
  558. Synopsis: my ($north, $south, $center) = $map->get_centromere($lg_name)
  559. Arguments: a valid linkage group name
  560. Returns: a three member list, the first element corresponds
  561. to the north boundary of the centromere in cM
  562. the second corresponds to the south boundary of
  563. the centromere in cM, the third is the arithmetic mean
  564. of the two first values.
  565. Side effects: none
  566. Description:
  567. =cut
  568. sub get_centromere {
  569. my $self=shift;
  570. my $lg = shift;
  571. if (! $self->has_linkage_group($lg)) {
  572. die "Not a valid linkage group for this map!\n";
  573. }
  574. my $lg_hash = $self->get_linkage_group_hash($lg);
  575. # foreach my $k (keys %$lg_hash) {
  576. # print " $k, $lg_hash->{$k}\n";
  577. # }
  578. my $north = $lg_hash->{north_centromere} || 0;
  579. my $south = $lg_hash->{south_centromere} || 0;
  580. return ($north, $south, int(($north+$south)/2));
  581. }
  582. sub get_linkage_group_hash {
  583. my $self= shift;
  584. my $lg_name = shift;
  585. foreach my $lg_hash (@{$self->linkage_groups()}) {
  586. if ($lg_hash->{lg_name} eq $lg_name) {
  587. return $lg_hash;
  588. }
  589. }
  590. }
  591. 1;