added a comment section..
[sgn.git] / cgi-bin / phenome / locus_display.pl
blob0887d45146640bf3b5e4fe3e755abe68f4414833
1 use strict;
2 use warnings;
3 use CXGN::Page;
5 use CXGN::Apache::Error;
6 use CXGN::DB::Connection;
7 use CXGN::People::PageComment;
8 use CXGN::People;
9 use CXGN::Contact;
10 use CXGN::Page::FormattingHelpers qw(
11 info_section_html
12 page_title_html
13 columnar_table_html
14 info_table_html
15 html_optional_show
16 html_alternate_show
17 tooltipped_text
19 use CXGN::Page::Widgets qw / collapser /;
20 use CXGN::Phenome::Locus;
21 use CXGN::Phenome::Locus::LinkageGroup;
23 use CXGN::Cview::ChrMarkerImage;
24 use CXGN::Cview::MapFactory;
25 use CXGN::Marker;
26 use CXGN::Cview::Marker::RangeMarker;
27 use CXGN::Map;
29 use CXGN::Chado::CV;
30 use CXGN::Chado::Feature;
31 use CXGN::Chado::Publication;
32 use CXGN::Chado::Pubauthor;
35 use CXGN::Sunshine::Browser;
36 use CXGN::Tools::Identifiers qw/parse_identifier/;
37 use CXGN::Tools::List qw/distinct/;
39 use CXGN::Phenome::Locus::LocusPage;
40 use SGN::Image;
41 use HTML::Entities;
43 my $d = CXGN::Debug->new();
44 ##$d->set_debug( 1 );
47 my $page= CXGN::Page->new("Locus display", "Naama");
48 my $dbh=$page->get_dbh();
50 my $time = time();
51 $d->d("start time = $time ! \n");
53 my %args = $page->cgi_params();
54 my $locus_id = $args{locus_id};
56 my $person_id = CXGN::Login->new($dbh)->has_session();
57 my $user = CXGN::People::Person->new($dbh, $person_id);
58 my $user_type = $user->get_user_type();
59 my $script = "/phenome/locus_display.pl?locus_id=$locus_id";
61 unless ( ( $locus_id =~ m /^\d+$/ ) || ($args{action} eq 'new' && !$locus_id) ) {
62 $c->throw(is_error=>0,
63 message=>"No locus exists for identifier $locus_id",
65 $d->d("No locus exists for identifier $locus_id");
68 my $locus= CXGN::Phenome::Locus->new( $dbh, $locus_id );
69 if ( $locus->get_obsolete() eq 't' && $user_type ne 'curator' )
71 $d->d("locus is obsolete!!" );
73 $c->throw(is_error=>0,
74 title => 'Obsolete locus',
75 message=>"Locus $locus_id is obsolete!",
76 developer_message => 'only curators can see obsolete loci',
77 notify => 0, #< does not send an error email
79 #$page->message_page("Locus $locus_id is obsolete!");
83 my $locus_name = $locus->get_locus_name();
84 my $organism = $locus->get_common_name();
86 $page->jsan_use("CXGN.Phenome.Tools");
87 $page->jsan_use("CXGN.Phenome.Locus");
88 $page->jsan_use("MochiKit.DOM");
89 $page->jsan_use("Prototype");
90 $page->jsan_use("jQuery");
91 $page->jsan_use("thickbox");
92 $page->jsan_use("MochiKit.Async");
93 $page->jsan_use("CXGN.Sunshine.NetworkBrowser");
94 $page->jsan_use("CXGN.Phenome.Locus.LocusPage");
95 $page->jsan_use("CXGN.Page.Form.JSFormPage");
97 #used to show certain elements to only the proper users
99 my @owners = $locus->get_owners();
101 my $action = $args{action};
103 if ( !$locus->get_locus_id() && $action ne 'new' && $action ne 'store' ) {
104 $c->throw(is_error=>0, message=>'No locus exists for this identifier',);
105 $d->d('No locus exists for this identifier');
106 #$page->message_page("No locus exists for this identifier");
109 $page->header("SGN $organism locus: $locus_name");
111 print page_title_html("$organism \t'$locus_name'\n");
113 print CXGN::Phenome::Locus::LocusPage::initialize($locus_id);
115 $d->d("!!!Printing page title : " . ( time() - $time ) . "\n");
116 ####################################################
117 #get all dbxref annotations: pubmed, ncbi sequences, GO, PO, tgrc link
118 ####################################################
119 my @allele_objs = $locus->get_alleles(); #array of allele objects
120 my ( $tgrc, $pubs, $pub_count, $genbank, $gb_count, $onto_ref ) =
121 get_dbxref_info($locus, @allele_objs);
123 $d->d( "!!!Got all dbxrefs! : " . ( time() - $time ) . "\n");
125 ##############################
126 #display locus details section
127 #############################
128 my $curator_html;
129 my ( $synonyms, $symbol, $symbol_link, $activity, $description, $lg_name,
130 $arm, $locus_details );
131 my $editor_note =
132 qq |<a href="/phenome/editors_note.pl">Note to Editors</a>|;
133 my $guide_html =
134 qq|<a href="http://docs.google.com/View?docid=ddhncntn_0cz2wj6">Annotation guidelines</a>|;
136 my $locus_html= qq| <table width="100%"><tr><td>|
137 . CXGN::Phenome::Locus::LocusPage::init_locus_form($locus_id);
138 #Only show if you are a curator or the object owner and there is no registry already assocaited with the locus
139 if (
141 $user_type eq 'curator'
142 || grep { /^$person_id$/ } @owners
144 && !( $locus->get_associated_registry() )
147 if ($locus_name) { $locus_html .= associate_registry($locus, $person_id); }
148 else {
149 $curator_html .=
150 qq |<span class = "ghosted"> [Associate registry name]</span> |;
154 #merge locus form
155 if ( $user_type eq 'curator' ) {
156 $curator_html .= "<br />" . merge_locus($locus, $person_id);
159 my $locus_synonym_count = scalar( $locus->get_locus_aliases('f', 'f') ) || "";
160 $locus_html .=
161 qq { <br /><br /><b>Locus synonyms</b> <b>$locus_synonym_count:</b> };
163 foreach my $synonym ( $locus->get_locus_aliases('f','f') ) {
164 $locus_html .= $synonym->get_locus_alias() . " ";
167 if ($locus_name) {
168 $locus_html .=
169 qq|<a href="locus_synonym.pl?locus_id=$locus_id&amp;action=new">[Add/Remove]</a><br />|;
171 $locus_html .= "<br />" . $tgrc;
173 #print editors info
174 $locus_html .= print_locus_editor_info($locus) . "<br>";
176 #change ownership:
177 if ( $user_type eq 'curator' ) {
178 $curator_html .= assign_owner($locus);
180 if ( ( !( grep { $_ =~ /^$person_id$/ } @owners ) )
181 && ( $user_type ne 'curator' ) )
184 $locus_html .=
185 qq|<a href="claim_locus_ownership.pl?locus_id=$locus_id&amp;action=confirm"> [Request editor privileges]</a><br /><br />|;
188 my $created_date = $locus->get_create_date();
189 $created_date = substr $created_date, 0, 10;
190 my $modified_date = $locus->get_modification_date() || "";
191 $modified_date = substr $modified_date, 0, 10;
193 my $updated_by = $locus->get_updated_by();
194 my $updated =
195 CXGN::People::Person->new( $locus->get_dbh(), $updated_by );
196 my $u_first_name = $updated->get_first_name();
197 my $u_last_name = $updated->get_last_name();
198 $locus_html .= qq |Created on: $created_date |;
199 if ($modified_date) {
200 $locus_html .=
201 qq | Last updated on: $modified_date by <a href="/solpeople/personal-info.pl?sp_person_id=$updated_by">$u_first_name $u_last_name</a><br />|;
204 #build a chromosome, map/s and marker/s objects
205 $locus_html .= get_location($locus);
208 my $name = $locus->get_associated_registry();
209 if ($name) {
210 $locus_html .= "This locus is associated with registry name: $name<br />";
213 ##############history ############
215 if ( $user_type eq 'curator'
216 || grep { /^$person_id$/ } @owners )
218 my $history_data = print_locus_history($locus) || "";
219 $locus_html .= $history_data;
221 my $locus_xml = $locus_id ? qq |<a href = "generic_gene_page.pl?locus_id=$locus_id">Download GMOD XML</a>|
222 : qq |<span class="ghosted">Download GMOD XML</span>|;
224 #print locus details section
225 print info_section_html(
226 title => 'Locus details',
227 subtitle => $locus_xml . " |" . " "
228 . $editor_note . " " . "|" . " "
229 . $guide_html,
230 contents => $locus_html,
232 if ($curator_html) {
233 print info_section_html(
234 title => 'Curator tools',
235 subtitle => "",
236 contents => $curator_html,
237 collapsible => 1,
238 collapsed => 1,
241 print STDERR "!!!Printing locus_details : " . ( time() - $time ) . "\n";
243 ##########
244 ## Notes and Figures
245 ##########
247 my $figure_html = "";
248 my $m_figure_html = "";
249 my $figure_subtitle = "";
250 my $figures_count;
251 my @more_is;
254 if (
255 $locus_name
256 && ( $user_type eq 'submitter'
257 || $user_type eq 'curator'
258 || $user_type eq 'sequencer' )
261 $figure_subtitle .= associated_figures($locus, $person_id);
263 else {
264 $figure_subtitle .=
265 qq|<span class= "ghosted">[Add notes, figures or images]</span> |;
268 my @figures = $locus->get_figure_ids();
270 if (@figures) { # don't display anything for empty list of figures
271 $figure_html .= qq|<table cellpadding="5">|;
272 foreach my $figure_id (@figures) {
273 $figures_count++;
274 my $figure= SGN::Image->new($locus->get_dbh(), $figure_id);
275 my $figure_name = $figure->get_name();
276 my $figure_description = $figure->get_description();
277 my $figure_img = $figure->get_image_url("medium");
278 my $small_image = $figure->get_image_url("thumbnail");
279 my $image_page = "/image/index.pl?image_id=$figure_id";
281 my $thickbox =
282 qq|<a href="$figure_img" title="<a href=$image_page>Go to image page ($figure_name)</a>" class="thickbox" rel="gallery-figures"><img src="$small_image" alt="$figure_description" /></a> |;
283 my $fhtml =
284 qq|<tr><td width=120>|
285 . $thickbox
286 . $figure_name
287 . "</td><td>"
288 . $figure_description
289 . "</td></tr>";
290 if ( $figures_count < 3 ) { $figure_html .= $fhtml; }
291 else {
292 push @more_is, $fhtml;
293 } #more than 3 figures- show these in a hidden div
295 $figure_html .= "</table>"; #close the table tag or the first 3 figures
297 $m_figure_html .=
298 "<table cellpadding=5>"; #open table tag for the hidden figures #4 and on
299 my $more = scalar(@more_is);
300 foreach (@more_is) { $m_figure_html .= $_; }
302 $m_figure_html .= "</table>"; #close tabletag for the hidden figures
303 my $more_images;
304 if (@more_is) { #html_optional_show if there are more than 3 figures
305 $more_images = html_optional_show(
306 "Images",
307 "<b>See $more more figures...</b>",
308 qq| $m_figure_html |,
309 0, #< do not show by default
310 'abstract_optional_show', #< don't use the default button-like style
313 print info_section_html(
314 title => "Notes and figures (" . scalar(@figures) . ")",
315 subtitle => $figure_subtitle,
316 contents => $figure_html . $more_images,
317 collapsible => 1,
318 collapsed => 1,
320 print STDERR "!!!Printing notes and figures : "
321 . ( time() - $time ) . "\n";
323 #################################
324 #display individuals section
325 #################################
326 my $individuals_html = "";
327 my $ind_subtitle = "";
328 if (
329 $locus_name
330 && ( $user_type eq 'curator'
331 || $user_type eq 'submitter'
332 || $user_type eq 'sequencer' )
335 $ind_subtitle .=
336 qq| <a href="javascript:Tools.toggleContent('associateIndividualForm', 'locus_accessions')">[Associate accession]</a> |;
337 $individuals_html = associate_individual($locus, $person_id);
339 else {
340 $ind_subtitle .=
341 qq|<span class= "ghosted">[Associate accession]</span> |;
343 my ( $html, $ind_count ) = get_individuals_html($locus, $user_type);
344 $individuals_html .= $html;
346 print info_section_html(
347 title => "Accessions and images ($ind_count)",
348 subtitle => $ind_subtitle,
349 contents => $individuals_html,
350 id => "locus_accessions",
351 collapsible => 1,
352 collapsed => 1,
354 print STDERR "!!!Printing individuas section : "
355 . ( time() - $time ) . "\n";
357 #################################
358 #display alleles section
359 #################################
361 my $allele_count = scalar(@allele_objs);
363 #map the allele objects to an array ref of the alleles data
364 my @allele_data;
365 my $allele_data;
366 my $allele_subtitle;
367 if (
368 $locus_name
369 && ( $user_type eq 'submitter'
370 || $user_type eq 'curator'
371 || $user_type eq 'sequencer' )
374 $allele_subtitle .=
375 qq { <a href="allele.pl?locus_id=$locus_id&amp;action=new">[Add new allele]</a>};
377 else {
378 $allele_subtitle .=
379 qq | <span class="ghosted">[Add new Allele]</span> |;
382 foreach my $a (@allele_objs) {
384 my $allele_id = $a->{allele_id};
386 my $allele_synonyms;
387 my @allele_aliases = $a->get_allele_aliases();
388 foreach my $a_synonym (@allele_aliases) {
389 $allele_synonyms .= $a_synonym->get_allele_alias() . " ";
391 if ( !$allele_synonyms ) { $allele_synonyms = "[add new]"; }
392 my $allele_synonym_link =
393 qq |<a href= "allele_synonym.pl?allele_id=$allele_id&amp;action=new">$allele_synonyms</a> |;
394 my $allele_edit_link = get_allele_edit_links($a, $user);
395 my $phenotype = $a->get_allele_phenotype();
396 my @individuals = $a->get_individuals();
397 my $individual_link = "";
398 my $ind_count = scalar(@individuals);
400 $individual_link .=
401 qq|<a href="allele.pl?action=view&amp;allele_id=$allele_id">$ind_count </a>|;
403 push @allele_data,
405 map { $_ } (
406 "<i>" . $a->get_allele_symbol . "</i>",
407 $a->get_allele_name,
408 $allele_synonym_link,
409 qq|<div align="left"><a href="allele.pl?action=view&amp;allele_id=$allele_id"> |
410 . $phenotype
411 . "</a></div>",
412 $individual_link,
413 $allele_edit_link,
418 if (@allele_data) {
420 $allele_data .= columnar_table_html(
421 headings => [
422 'Allele symbol', 'Allele name',
423 'Synonyms', 'Phenotype',
424 'Accessions',
426 data => \@allele_data,
427 __alt_freq => 2,
428 __alt_width => 1,
429 __alt_offset => 3,
433 print info_section_html(
434 title => "Known alleles ($allele_count)",
435 subtitle => $allele_subtitle,
436 contents => $allele_data,
437 collapsible => 1,
438 collapsed => 1,
440 print STDERR "!!!Printing alleles : " . ( time() - $time ) . "\n";
444 ########################### ASSOCIATED LOCI
445 #my @locus_groups= $locus->get_locusgroups();
446 #my $direction;
447 my $al_count = $locus->count_associated_loci();
449 my $associated_locus_sub;
450 my $associate_locus_form;
451 if (
453 $user_type eq 'curator'
454 || $user_type eq 'submitter'
455 || $user_type eq 'sequencer'
460 if ($locus_name) {
461 $associated_locus_sub .=
462 qq |<a href="javascript:Tools.toggleContent('associateLocusForm', 'locus2locus');Tools.getOrganisms()">[Associate new locus]</a> |;
463 $associate_locus_form =
464 CXGN::Phenome::Locus::LocusPage::associate_locus_form($locus_id);
467 else {
468 $associated_locus_sub .=
469 qq |<span class ="ghosted"> [Associate new locus] </span> |;
472 #printing associated loci section dynamically
473 my $dyn = CXGN::Phenome::Locus::LocusPage::include_locus_network();
475 print info_section_html(
476 title => "Associated loci ($al_count) ",
477 subtitle => $associated_locus_sub,
478 contents => $associate_locus_form . $dyn,
479 id => 'locus2locus',
480 collapsible => 1,
481 collapsed => 1,
484 $d->d( "!!!Printing locus2locus : " . ( time() - $time ) . "\n");
486 ################## SUNSHINE BROWSER
488 my $locus2locus_graph =
489 CXGN::Sunshine::Browser::include_on_page( 'locus', $locus_id );
491 my $networkbrowser_link =
492 qq { View <b>$locus_name</b> relationships in the stand-alone <a href="/tools/networkbrowser/?type=locus&name=$locus_id">network browser</a>. Please note that this tool is a prototype.<br /><br /><br /> };
494 if ( $al_count > 0 ) {
495 print info_section_html(
496 title => "Associated loci - graphical view [beta version]",
497 contents => $networkbrowser_link . $locus2locus_graph,
498 id => 'locus2locus_graph',
499 collapsible => 1,
500 collapsed => 1,
503 else {
504 print info_section_html(
505 title => "Associated loci - graphical view",
506 collapsible => 0,
507 collapsed => 1,
508 id => 'locus2locus_graph'
514 ##################### UNIGENES AND SOLCYC
516 my @unigenes = $locus->get_unigenes();
517 my $unigene_count=0;
518 my $solcyc_count=0;
519 foreach (@unigenes) {
520 $unigene_count++ if $_->get_status eq 'C';
523 my $dyn_solcyc = CXGN::Phenome::Locus::LocusPage::include_solcyc_links();
525 print info_section_html(
526 title => "SolCyc links",
527 contents => $dyn_solcyc,
528 id => 'solcyc',
529 collapsible => 1,
530 collapsed => 1,
532 $d->d( "!!!Got SolCyc links : " . ( time() - $time ) . "\n");
534 my $associate_unigene_form;
535 if (
537 $user_type eq 'curator'
538 || $user_type eq 'submitter'
539 || $user_type eq 'sequencer'
543 if ($locus_name) {
544 $associate_unigene_form= qq|<a href="javascript:Tools.toggleContent('associateUnigeneForm', 'unigenes' )">[Associate new unigene]</a> |;
545 $associate_unigene_form .=
546 CXGN::Phenome::Locus::LocusPage::associate_unigene_form($locus_id);
549 my $sequence_links;
550 if ($locus_name) {
551 if ( !$genbank ) {
552 $genbank = qq|<span class=\"ghosted\">none </span>|;
554 $genbank .=
555 qq|<a href="/chado/add_feature.pl?type=locus&amp;type_id=$locus_id&amp;refering_page=$script&amp;action=new">[Associate new genbank sequence]</a><br />|;
558 #printing associated unigenes section dynamically
559 my $dyn_unigenes = CXGN::Phenome::Locus::LocusPage::include_locus_unigenes();
560 $d->d( "!!!Got unigenes : " . ( time() - $time ) . "\n");
562 $sequence_links = info_table_html(
563 'SGN Unigenes' => $dyn_unigenes . $associate_unigene_form,
564 'GenBank Accessions' => $genbank,
565 'Genome Matches' => genomic_annots_html($locus),
566 __border => 0,
569 my $seq_count = $gb_count + $unigene_count;
570 print info_section_html(
571 title => "Sequence annotations ($seq_count)",
572 contents => $sequence_links,
573 id => 'unigenes',
574 collapsible => 1,
575 collapsed => 1,
577 $d->d("!!!got sequence : " . ( time() - $time ) . "\n");
579 ##########literature ########################################
580 my ( $pub_links, $pub_subtitle );
581 if ($pubs) {
582 $pub_links = info_table_html(
583 " " => $pubs,
584 __border => 0,
588 if (
589 $locus_name
590 && ( $user_type eq 'curator'
591 || $user_type eq 'submitter'
592 || $user_type eq 'sequencer' )
595 $pub_subtitle .=
596 qq|<a href="/chado/add_publication.pl?type=locus&amp;type_id=$locus_id&amp;refering_page=$script&amp;action=new"> [Associate publication] </a>|;
598 else {
599 $pub_subtitle =
600 qq|<span class=\"ghosted\">[Associate publication]</span>|;
603 my $disabled = "true";
604 if ($person_id) { $disabled = "false"; }
605 $pub_subtitle .=
606 qq | <a href="javascript:void(0)"onclick="window.open('locus_pub_rank.pl?locus_id=$locus_id','publication_list','width=600,height=400,status=1,location=1,scrollbars=1')">[Matching publications]</a> |;
608 $d->d("!!!Printing pub links : " . ( time() - $time ) . "\n");
610 print info_section_html(
611 title => "Literature annotation ($pub_count)",
612 subtitle => $pub_subtitle,
613 contents => $pub_links,
614 collapsible => 1,
615 collapsed => 1,
618 ######################################## Ontology details ##############
620 my $ont_count = $locus->count_ontology_annotations(); #= scalar(@$onto_ref);
622 my $ontology_add_link = "";
623 my $ontology_subtitle;
624 if (
626 $user_type eq 'curator'
627 || $user_type eq 'submitter'
628 || $user_type eq 'sequencer'
632 if ($locus_name) {
633 $ontology_subtitle .=
634 qq|<a href="javascript:Tools.toggleContent('associateOntologyForm', 'locus_ontology')">[Add ontology annotations]</a> |;
635 $ontology_add_link =
636 CXGN::Phenome::Locus::LocusPage::associate_ontology_form(
637 $locus_id);
640 else {
641 $ontology_subtitle =
642 qq |<span class = "ghosted"> [Add ontology annotations]</span> |;
645 my $dyn_ontology_info =
646 CXGN::Phenome::Locus::LocusPage::include_locus_ontology();
648 print info_section_html(
649 title => "Ontology annotations ($ont_count)",
650 subtitle => $ontology_subtitle,
651 contents => $ontology_add_link . $dyn_ontology_info,
652 id => "locus_ontology",
653 collapsible => 1,
654 collapsed => 1,
657 $d->d( "!!!Printing ontology links! : " . ( time() - $time ) . "\n");
659 ####add page comments
660 if ($locus_name) {
661 my $page_comment_obj =
662 CXGN::People::PageComment->new( $locus->get_dbh(), "locus",
663 $locus_id );
664 print $page_comment_obj->get_html();
667 $page->footer();
671 #########################################################
672 #functions used in the locus page:
675 sub empty_search {
676 my ($page) = @_;
678 # $page->header();
680 print <<EOF;
682 <b>No locus was specified or this locus ID does not exist</b>
686 exit 0;
689 sub get_allele_edit_links {
690 my $allele = shift;
691 my $user= shift;
692 my $login_user_id = $user->get_sp_person_id();
693 my $locus = $allele->get_locus();
694 my $locus_id = $locus->get_locus_id();
696 my $allele_edit_link = "";
698 my $allele_id = $allele->get_allele_id();
699 if ( ( $allele->get_sp_person_id() == $login_user_id )
700 || ( $user->get_user_type() eq 'curator' ) )
702 $allele_edit_link =
703 qq | <a href="allele.pl?action=edit&amp;allele_id=$allele_id">[Edit]</a> |;
705 else { $allele_edit_link = qq | <span class="ghosted">[Edit]</span> |; }
708 sub get_location {
709 my $locus = shift;
711 my $lg_name = $locus->get_linkage_group();
712 my $arm = $locus->get_lg_arm();
713 my $location_html;
714 my @locus_marker_objs =
715 $locus->get_locus_markers(); #array of locus_marker objects
716 foreach my $lmo (@locus_marker_objs) {
717 my $marker_id = $lmo->get_marker_id(); #{marker_id};
718 my $marker =
719 CXGN::Marker->new( $locus->get_dbh(), $marker_id )
720 ; #a new marker object
722 my $marker_name = $marker->name_that_marker();
723 my $experiments = $marker->current_mapping_experiments();
724 if ( $experiments
725 and @{$experiments}
726 and grep { $_->{location} } @{$experiments} )
728 my $count = 1;
729 for my $experiment ( @{$experiments} ) {
730 if ( my $loc = $experiment->{location} ) {
731 my $map_version_id = $loc->map_version_id();
732 my $lg_name = $loc->lg_name();
734 if ($map_version_id) {
735 my $map_factory =
736 CXGN::Cview::MapFactory->new( $locus->get_dbh() );
737 my $map = $map_factory->create(
738 { map_version_id => $map_version_id } );
739 my $map_version_id = $map->get_id();
740 my $map_name = $map->get_short_name();
742 my $chromosome =
743 CXGN::Cview::ChrMarkerImage->new( "", 100, 150,
744 $locus->get_dbh(), $lg_name, $map, $marker_name );
745 my ( $image_path, $image_url ) =
746 $chromosome->get_image_filename();
747 my $chr_link =
748 qq|<img src="$image_url" usemap="#map$count" border="0" alt="" />|;
749 $chr_link .=
750 $chromosome->get_image_map("map$count") . "<br />";
751 $chr_link .= $map_name;
752 $count++;
754 $location_html .= "<td>" . $chr_link . "</td>";
761 #draw chromosome with marker-range for loci w/o associated marker, only a chromosome arm annotation
762 if ( scalar(@locus_marker_objs) == 0 && $lg_name ) {
763 my $organism = $locus->get_common_name();
764 my %org_hash = (
765 'Tomato' => 9, #F2 2000 map
766 'Potato' => 3,
767 'Eggplant' => 6,
768 'Pepper' => 10
770 my $map_id = $org_hash{$organism};
771 my $map_factory = CXGN::Cview::MapFactory->new( $locus->get_dbh() );
773 my $map = $map_factory->create( { map_id => $map_id } );
774 if ($map) {
775 my $map_name = $map->get_short_name();
776 my ( $north, $south, $center ) = $map->get_centromere($lg_name);
778 my $dummy_name;
779 $dummy_name = "$arm arm" if $arm;
780 my $chr_image =
781 CXGN::Cview::ChrMarkerImage->new( "", 150, 150, $locus->get_dbh(),
782 $lg_name, $map, $dummy_name );
784 my ($chr) = $chr_image->get_chromosomes();
786 my $range_marker = CXGN::Cview::Marker::RangeMarker->new($chr);
788 my ( $offset, $nrange, $srange );
789 if ( $arm eq 'short' ) {
790 $offset = $nrange = $srange = $center / 2;
792 elsif ( $arm eq 'long' ) {
793 my $stelomere = $chr->get_length();
794 $offset = ( $center + $stelomere ) / 2;
795 $nrange = $srange = ( $stelomere - $center ) / 2;
798 $range_marker->set_offset($offset); #center of north/south arm
799 $range_marker->set_north_range($nrange);
800 $range_marker->set_south_range($srange);
801 $range_marker->set_marker_name($dummy_name);
802 if ( !$dummy_name ) { $range_marker->hide_label(); }
804 #$range_marker->show_label();
805 #}else {
806 $range_marker->set_label_spacer(20);
808 $range_marker->get_label()->set_name($dummy_name);
809 $range_marker->get_label->set_stacking_level(2);
811 $chr->add_marker($range_marker);
813 my ( $image_path, $image_url ) = $chr_image->get_image_filename();
814 my $chr_link =
815 qq|<img src="$image_url" usemap="#chr_arm_map" border="0" alt="" />|;
816 $chr_link .= $chr_image->get_image_map("chr_arm_map") . "<br />";
817 $chr_link .= $map_name;
819 $location_html .= "<td>" . $chr_link . "</td>";
823 $location_html .= "</td></tr></table>";
824 return $location_html;
825 } #get_location
827 sub print_locus_history {
828 my $locus = shift;
829 my @history;
830 my $history_data;
831 my $print_history;
832 my @history_objs = $locus->show_history(); #array of locus_history objects
834 foreach my $h (@history_objs) {
836 my $created_date = $h->get_create_date();
837 $created_date = substr $created_date, 0, 10;
839 my $history_id = $h->{locus_history_id};
840 my $updated_by_id = $h->{updated_by};
841 my $updated =
842 CXGN::People::Person->new( $locus->get_dbh(), $updated_by_id );
843 my $u_first_name = $updated->get_first_name();
844 my $u_last_name = $updated->get_last_name();
845 my $up_person_link =
846 qq |<a href="/solpeople/personal-info.pl?sp_person_id=$updated_by_id">$u_first_name $u_last_name</a> ($created_date)|;
848 push @history,
850 map { $_ } (
851 $h->get_locus_symbol, $h->get_locus_name,
852 $h->get_gene_activity, $h->get_description,
853 $h->get_linkage_group, $h->get_lg_arm,
854 $up_person_link,
859 if (@history) {
861 $history_data .= columnar_table_html(
862 headings => [
863 'Symbol', 'Name', 'Activity', 'Description',
864 'Chromosome', 'Arm', 'Updated by',
866 data => \@history,
867 __alt_freq => 2,
868 __alt_width => 1,
869 __alt_offset => 3,
871 $print_history = html_optional_show(
872 'locus_history',
873 'Show locus history',
874 qq|<div class="minorbox">$history_data</div> |,
878 return $print_history;
879 } #print_locus_history
881 sub get_dbxref_info {
882 my $locus = shift;
883 my $locus_name = $locus->get_locus_name();
884 my %dbs = $locus->get_dbxref_lists()
885 ; #hash of arrays. keys=dbname values= dbxref objects
886 my (@alleles) = @_; #$locus->get_alleles();
887 #add the allele dbxrefs to the locus dbxrefs hash...
888 #This way the alleles associated publications and sequences are also printed on the locus page
889 #it might be a good idea to pring a link to the allele next to each allele-derived annotation
891 foreach my $a (@alleles) {
892 my %a_dbs = $a->get_dbxref_lists();
894 foreach my $a_db_name ( keys %a_dbs )
895 { #add allele_dbxrefs to the locus_dbxrefs list
896 my %seen = ()
897 ; #hash for assisting filtering of duplicated dbxrefs (from allele annotation)
898 foreach ( @{ $dbs{$a_db_name} } ) {
899 $seen{ $_->[0]->get_accession() }++;
900 } #populate with the locus_dbxrefs
901 foreach ( @{ $a_dbs{$a_db_name} } ) { #and filter duplicates
902 push @{ $dbs{$a_db_name} }, $_
903 unless $seen{ $_->[0]->get_accession() }++;
907 my ( $tgrc, $pubs, $genbank );
908 ##tgrc
909 foreach ( @{ $dbs{'tgrc'} } ) {
910 if ( $_->[1] eq '0' ) {
911 my $url = $_->[0]->get_urlprefix() . $_->[0]->get_url();
912 my $accession = $_->[0]->get_accession();
913 $tgrc .=
914 qq|$locus_name is a <a href="$url$accession" target="blank">TGRC gene</a><br />|;
918 my $abs_count = 0;
919 foreach ( @{ $dbs{'PMID'} } ) {
920 if ( $_->[1] eq '0' ) { #if the pub is not obsolete
921 $pubs .= get_pub_info( $_->[0], 'PMID', $abs_count++ );
924 foreach ( @{ $dbs{'SGN_ref'} } ) {
925 $pubs .= get_pub_info( $_->[0], 'SGN_ref', $abs_count++ )
926 if $_->[1] eq '0';
929 my $gb_count = 0;
930 foreach ( @{ $dbs{'DB:GenBank_GI'} } ) {
931 if ( $_->[1] eq '0' ) {
932 $gb_count++;
933 my $url = $_->[0]->get_urlprefix() . $_->[0]->get_url();
934 my $gb_accession =
935 $locus->CXGN::Chado::Feature::get_feature_name_by_gi(
936 $_->[0]->get_accession() );
937 my $description = $_->[0]->get_description();
938 $genbank .=
939 qq|<a href="$url$gb_accession" target="blank">$gb_accession</a> $description<br />|;
942 my @ont_annot;
944 # foreach ( @{$dbs{'GO'}}) { push @ont_annot, $_; }
945 # foreach ( @{$dbs{'PO'}}) { push @ont_annot, $_; }
946 # foreach ( @{$dbs{'SP'}}) { push @ont_annot, $_; }
948 return ( $tgrc, $pubs, $abs_count, $genbank, $gb_count, \@ont_annot );
951 ########################
953 sub abstract_view {
954 my $pub = shift;
955 my $abs_count = shift;
956 my $abstract = encode_entities($pub->get_abstract() );
957 my $authors = encode_entities($pub->get_authors_as_string() );
958 my $journal = $pub->get_series_name();
959 my $pyear = $pub->get_pyear();
960 my $volume = $pub->get_volume();
961 my $issue = $pub->get_issue();
962 my $pages = $pub->get_pages();
963 my $abstract_view = html_optional_show(
964 "abstracts$abs_count",
965 'Show/hide abstract',
966 qq|$abstract <b> <i>$authors.</i> $journal. $pyear. $volume($issue). $pages.</b>|,
967 0, #< do not show by default
968 'abstract_optional_show', #< don't use the default button-like style
970 return $abstract_view;
973 sub get_pub_info {
974 my ( $dbxref, $db, $count ) = @_;
975 my $pub_info;
976 my $accession = $dbxref->get_accession();
977 my $pub_title = $dbxref->get_publication()->get_title();
978 my $year= $dbxref->get_publication()->get_pyear();
979 my $pub_id = $dbxref->get_publication()->get_pub_id();
980 my $abstract_view =
981 abstract_view( $dbxref->get_publication(), $count );
982 $pub_info =
983 qq|<div><a href="/chado/publication.pl?pub_id=$pub_id" >$db:$accession</a> $pub_title ($year). $abstract_view </div> |;
984 return $pub_info;
987 sub print_locus_editor_info {
988 my $locus=shift;
989 my $html = "Locus editors: ";
990 my @owners = $locus->get_owners();
992 foreach my $id (@owners) {
993 my $person = CXGN::People::Person->new( $locus->get_dbh(), $id );
995 my $first_name = $person->get_first_name();
996 my $last_name = $person->get_last_name();
997 if ($person->get_user_type() eq 'curator' && scalar(@owners) == 1 ) {
998 $html .= '<b>No editor assigned</b>';
999 } else {
1000 $html .=
1001 qq |<a href="/solpeople/personal-info.pl?sp_person_id=$id">$first_name $last_name</a>;|;
1004 chop $html;
1005 return $html;
1008 sub get_individuals_html {
1009 my $locus = shift;
1010 my $user_type=shift;
1011 my @individuals = $locus->get_individuals();
1013 my $html;
1014 my %imageHoA
1015 ; # hash of image arrays. Keys are individual_ids, values are arrays of image_ids
1016 my %individualHash;
1017 my %imageHash;
1018 my @no_image;
1019 my $more_html;
1020 my $more; #count the number of accessions in the optional_show box
1021 my $count
1022 ; # a scalar for checking if there are accessions with images in the optional box
1024 if (@individuals) {
1025 $html .= "<table>";
1026 $more_html .= "<table>";
1028 my %imageHoA
1029 ; # hash of image arrays. Keys are individual ids values are arrays of image ids
1030 foreach my $i (@individuals) {
1031 my $individual_id = $i->get_individual_id();
1032 my $individual_name = $i->get_name();
1033 $individualHash{$individual_id} = $individual_name;
1035 my @images =
1036 $i->get_images(); #array of all associated image objects
1037 foreach my $image (@images) {
1038 my $image_id = $image->get_image_id();
1040 #my $img_src_tag= $image->get_img_src_tag("thumbnail");
1041 $imageHash{$image_id} = $image;
1042 push @{ $imageHoA{$individual_id} }, $image_id;
1045 #if there are no associated images with this individual:
1046 if ( !@images ) { push @no_image, $individual_id; }
1048 my $ind_count = 0;
1050 # Print the whole thing sorted by number of members and name.
1052 my $individual_id ( sort { @{ $imageHoA{$b} } <=> @{ $imageHoA{$a} } }
1053 keys %imageHoA )
1055 $ind_count++;
1056 my $individual_name = $individualHash{$individual_id};
1057 my $individual_obsolete_link =
1058 get_individual_obsolete_link($locus,$individual_id, $user_type);
1059 my $link =
1060 qq|<a href="individual.pl?individual_id=$individual_id">$individual_name </a> |;
1061 if ( $ind_count < 4 )
1062 { #print the first 3 individuals by default. The rest will be hidden
1063 $html .=
1064 qq|<tr valign="top"><td>$link</td> <td> $individual_obsolete_link </td>|;
1066 else {
1067 $count++;
1068 $more++;
1069 $more_html .=
1070 qq|<tr><td>$link </td><td> $individual_obsolete_link</td> |;
1073 #print only 5 images, if there are more write the number of total images
1074 my $image_count = ( $#{ $imageHoA{$individual_id} } ); #+1;
1075 if ( $image_count > 4 ) { $image_count = 4; }
1076 for my $i ( 0 .. $image_count ) {
1077 my $image_id = $imageHoA{$individual_id}[$i];
1078 #my $image = $imageHash{$image_id};
1079 my $image = SGN::Image->new($locus->get_dbh(), $image_id);
1080 my $small_image = $image->get_image_url("thumbnail");
1081 my $medium_image = $image->get_image_url("medium");
1082 my $image_page = "/image/index.pl?image_id=$image_id";
1083 my $thickbox =
1084 qq|<a href="$medium_image" title="<a href=$image_page>Go to image page </a>" class="thickbox" rel="gallery-images"><img src="$small_image" alt="" /></a> |;
1085 if ( $ind_count < 4 ) { $html .= qq|<td>$thickbox</td>|; }
1086 else { $more_html .= qq|<td>$thickbox</td>|; }
1087 $image_count--;
1089 if ( $#{ $imageHoA{$individual_id} } > 4 ) {
1090 my $image_count = ( $#{ $imageHoA{$individual_id} } ) + 1;
1091 $html .= qq|<td>... (Total $image_count images)</td>|;
1093 if ( $ind_count < 4 ) { $html .= "</tr>"; }
1094 else { $more_html .= "</tr>"; }
1096 $html .= "</table><br />";
1097 $more_html .= "</table><br />";
1098 if ( !$count ) {
1099 my $individual_name;
1100 my $no_image_count = 0;
1101 foreach my $individual_id (@no_image) {
1102 $no_image_count++;
1103 my $individual_obsolete_link =
1104 get_individual_obsolete_link($locus, $individual_id, $user_type);
1105 if ( $no_image_count < 26 ) {
1106 $individual_name = $individualHash{$individual_id};
1107 $html .=
1108 qq|<a href="individual.pl?individual_id=$individual_id">$individual_name</a>&nbsp$individual_obsolete_link |;
1110 else {
1111 $more++;
1112 $more_html .=
1113 qq|<a href="individual.pl?individual_id=$individual_id">$individual_name</a>&nbsp$individual_obsolete_link |;
1117 else {
1118 foreach my $individual_id (@no_image) {
1119 $more++;
1120 my $individual_obsolete_link =
1121 get_individual_obsolete_link($locus, $individual_id, $user_type);
1122 my $individual_name = $individualHash{$individual_id};
1123 $more_html .=
1124 qq|<a href="individual.pl?individual_id=$individual_id">$individual_name</a>&nbsp$individual_obsolete_link |;
1129 if ($more) {
1130 my ( $more_link, $contents ) = collapser(
1132 linktext => "<b> See $more more accessions </b>",
1134 #hide_state_linktext => $title,
1135 content => $more_html,
1136 collapsed => 1,
1137 id => "more_individuals_display"
1140 $html .= "$more_link\n$contents";
1142 return ( $html, scalar(@individuals) );
1143 } #get_individuals_html
1145 ############################javascript code
1147 sub associate_registry {
1148 my $locus = shift;
1149 my $locus_id = $locus->get_locus_id();
1150 my $sp_person_id = shift;
1152 my $associate = qq^
1154 <a href=javascript:Locus.toggleAssociateRegistry()>[Associate a registry name with this locus]</a><br>
1155 <div id='associateRegistryForm' style="display: none">
1156 <div id='registry_search'>
1157 Registry Name:
1158 <input type="text"
1159 style="width: 50%"
1160 id="registry_input"
1161 onkeyup="Locus.getRegistries(this.value)">
1162 <input type="button"
1163 id="associate_registry_button"
1164 value="associate registry"
1165 disabled="true"
1166 onclick="Locus.associateRegistry('$locus_id','$sp_person_id');this.disabled=false;">
1168 <select id="registry_select"
1169 style="width: 100%"
1170 name="registry_select"
1171 size=10
1172 onchange="Locus.updateRegistryInput()">
1174 </select>
1176 Click <a href=javascript:Locus.addRegistryView()>here</a> to add a new registry name to our database
1177 </div>
1179 <div id="registry_add" style="display: none">
1180 <b>Please enter the values for the new registry name below (* is required)</b><br><br>
1181 <table cellspacing="0" cellpadding="0">
1182 <tr><td>*Registry Symbol: </td><td width="20">&nbsp;</td>
1183 <td><input type="text" id="registry_symbol" onblur="Locus.enableButton();" onchange="Locus.enableButton();"></td></tr>
1184 <tr><td>*Registry Name: </td><td width="20">&nbsp;</td>
1185 <td><input type="text" id="registry_name" onblur="Locus.enableButton();" onchange="Locus.enableButton();"></td></tr>
1186 </table>
1187 Registry Description:<br>
1188 <textarea id="registry_description" style="width: 100%"></textarea><br>
1189 <input type="button" disabled="true" id="add_registry_button" value="Add New Registry" onclick="Locus.addRegistry('$locus_id', '$sp_person_id');this.disabled=true;"><br>
1190 Click <a href=javascript:Locus.searchRegistries()>here</a> to go back to the registry search
1191 </div>
1192 </div>
1197 return $associate;
1200 sub associate_individual {
1202 my $locus = shift;
1203 my $locus_id = $locus->get_locus_id();
1204 my $sp_person_id = shift;
1206 my $associate_html = qq^
1208 <div id="associateIndividualForm" style="display: none">
1209 Accession name:
1210 <input type="text"
1211 style="width: 50%"
1212 id="locus_name"
1213 onkeyup="Locus.getIndividuals(this.value, '$locus_id');">
1214 <input type="button"
1215 id="associate_individual_button"
1216 value="associate accession"
1217 disabled="true"
1218 onclick="Locus.associateAllele('$sp_person_id');this.disabled=true;">
1219 <select id="individual_select"
1220 style="width: 100%"
1221 onchange="Locus.getAlleles('$locus_id')"
1222 size=10>
1223 </select>
1225 <b>Would you Like to specify an allele?</b>
1226 <select id="allele_select"
1227 style="width: 100%">
1228 </select>
1230 </div>
1233 return $associate_html;
1237 sub assign_owner {
1238 my $locus = shift;
1239 my $locus_id = $locus->get_locus_id();
1240 my $object_type = "locus";
1242 my $assign = qq^
1243 <a href=javascript:Tools.toggleAssignFormDisplay()>[Assign a locus owner]</a> Notice: 'user' account will be updated to 'submitter' <br>
1244 <div id='assignOwnerForm' style="display:none">
1245 <div id='user_search'>
1246 First name or last name:
1247 <input type="text"
1248 style="width: 50%"
1249 id="user_input"
1250 onkeyup="Tools.getUsers(this.value)">
1251 <input type="button"
1252 id="associate_button"
1253 value="assign owner"
1254 disabled="true"
1255 onclick="Tools.assignOwner('$locus_id', '$object_type');this.disabled=false;">
1257 <select id="user_select"
1258 style="width: 100%"
1259 onchange= "Tools.enableButton('associate_button');"
1260 size=5>
1261 </select>
1263 </div>
1264 </div>
1265 <BR>
1268 return $assign;
1271 sub associated_figures {
1273 my $locus = shift;
1274 my $locus_id = $locus->get_locus_id();
1275 my $sp_person_id = shift;
1277 my $associate_html = qq^
1278 <span>
1279 <a href="/image/add_image.pl?type_id=$locus_id&type=locus&action=new&refering_page=/phenome/locus_display.pl?locus_id=$locus_id">
1280 [Add notes, figures or images]</a></span>
1283 return $associate_html;
1287 sub get_individual_obsolete_link {
1288 my $locus = shift;
1289 my $individual_id = shift;
1290 my $user_type = shift;
1291 my $individual_obsolete_link = "";
1292 my $individual_allele_id = $locus->get_individual_allele_id($individual_id);
1293 if ( ( $user_type eq 'submitter' )
1294 || ( $user_type eq 'curator' )
1295 || ( $user_type eq 'sequencer' ) )
1297 $individual_obsolete_link = qq|
1298 <a href="javascript:Locus.obsoleteIndividualAllele('$individual_allele_id')">[Remove]</a>
1300 <div id='obsoleteIndividualAlleleForm' style="display: none">
1301 <div id='individual_allele_id_hidden'>
1302 <input type="hidden"
1303 value=$individual_allele_id
1304 id="$individual_allele_id">
1305 </div>
1306 </div>
1310 return $individual_obsolete_link;
1313 sub merge_locus {
1314 my $locus = shift;
1315 my $locus_id = $locus->get_locus_id();
1316 my $object_type = "locus";
1317 my $common_name = $locus->get_common_name();
1318 my $merge = qq^
1319 <a href=javascript:Tools.toggleMergeFormDisplay()>[Merge locus]</a> Warning: Merged locus will be set to obsolete! Unobsoleting is possible only directly via the database! <br>
1320 <div id='mergeLocusForm' style="display:none">
1322 <div id='locus_merge'>
1323 <input type="hidden"
1324 value=$common_name
1325 id ="common_name"
1327 locus name
1328 <input type="text"
1329 style="width: 50%"
1330 id="locus_input"
1331 onkeyup="Locus.getMergeLocus(this.value, $locus_id)">
1332 <input type="button"
1333 id="merge_locus_button"
1334 value="merge locus"
1335 disabled="true"
1336 onclick="Locus.mergeLocus('$locus_id');this.disabled=false;">
1338 <select id="locus_list"
1339 style="width: 100%"
1340 onchange= "Locus.enableMergeButton();"
1341 size=5>
1342 </select>
1343 </div>
1344 </div>
1345 <BR>
1348 return $merge;
1351 #returns string html listing of locus sequence matches found in ITAG gbrowse DBs
1352 sub genomic_annots_html {
1354 my $locus = shift;
1355 my $locus_id = $locus->get_locus_id();
1358 # look up any gbrowse cross-refs for this locus id, if any
1359 my @xrefs = map {
1360 $_->xrefs({ -types => ['match'],
1361 -attributes => { sgn_locus_id => $locus_id },
1363 } $c->enabled_feature('gbrowse2');
1365 return '<span class="ghosted">None</span>'
1366 unless @xrefs;
1369 # and now convert each of the matched regions into HTML strings
1370 # that display them
1371 return join "\n", map _render_genomic_xref( $_ ), @xrefs;
1374 sub _render_genomic_xref {
1375 my ( $xref ) = @_;
1377 # look up all the matching locus sequence names
1378 my @locus_seqnames =
1379 distinct
1380 map {
1381 my $f = $_;
1382 my $p = parse_identifier(
1383 $f->target->seq_id,
1384 'sgn_locus_sequence'
1385 ) or die "cannot parse " . $f->target->seq_id;
1386 $p->{ext_id}
1388 @{$xref->seqfeatures};
1390 my $linked_img = CGI->a( { href => $xref->url },
1391 CGI->img({ #style => "border: 1px solid #ddd; border-top: 0; padding: 1em 0; margin:0",
1392 style => 'border: none',
1393 src => $xref->preview_image_url })
1397 my $sequences_matched =
1398 @locus_seqnames > 1 ? 'Sequences matched'
1399 : 'Sequence matched';
1401 return join('',
1402 '<div style="border: 1px solid #777; padding-bottom: 10px">',
1403 info_table_html(
1404 'Annotation Set' => $xref->data_source->description,
1405 'Feature(s) matched' => join( ', ', map $_->display_name || $_->primary_id, @{$xref->seqfeatures} ),
1406 'Reference Sequence' => $xref->seqfeatures->[0]->seq_id,
1407 $sequences_matched => join( ', ', @locus_seqnames ),
1408 #__tableattrs => qq|summary="" style="margin: 1em auto -1px auto"|,
1409 __border => 0,
1410 __multicol => 3,
1412 '<hr style="width: 95%" />',
1413 $linked_img,
1414 '</div>',