package EnsEMBL::Web::Component::Location::MarkerDetails;
# outputs chunks of XHTML for marker-based displays
use base qw(EnsEMBL::Web::Component);
use EnsEMBL::Web::Document::HTML::TwoCol;
use Bio::EnsEMBL::Registry;
use strict;
use warnings;
no warnings "uninitialized";
my $MAX_MAP_WEIGHT = 15;
my $MAP_WEIGHT = 2;
my $PRIORITY = 50;
sub _init {
my $self = shift;
$self->ajaxable( 0 );
}
sub content {
my $self = shift;
my $object = $self->object;
my $species = $object->species;
my $html;
my $to_list = 1;
my $mfs = [];
my $markers = [];
my $found_mf = [];
if (my $m = $object->param('m')) {
my $adap = Bio::EnsEMBL::Registry->get_adaptor($species,'core','Marker');
$markers = $adap->fetch_all_by_synonym($m);
$html = $self->render_marker_details($markers);
}
else {
my $threshold = 1000100 * ($object->species_defs->ENSEMBL_GENOME_SIZE||1);
if( $object->length > $threshold ) {
return $self->_warning( 'Region too large',
'<p>The region selected is too large to display in this view</p>' );
}
foreach my $mf (@{$object->Obj->{'slice'}->get_all_MarkerFeatures()}) {
push @{$found_mf}, $mf;
}
$html = $self->render_marker_features($found_mf);
}
return $html;
}
# depending on number print a list of marker_features, or show details for markers
sub render_marker_features {
my $self = shift;
my ($found_mf) = @_;
my $object = $self->object;
my $species = $object->species;
my %mfs;
foreach my $mf (@$found_mf) {
my $name = $mf->marker->display_MarkerSynonym->name;
my $sr_name = $mf->seq_region_name;
my $cs = $mf->coord_system_name;
push @{$mfs{$name}->{$sr_name}}, {
'cs' => $cs,
'mf' => $mf,
'start' => $mf->seq_region_start,
'end' => $mf->seq_region_end, };
}
my $html;
my $c = keys %mfs;
#print a list if we have more than one marker
if ($c > 1 ) {
$html = qq(<h3>$c mapped markers found:</h3>);
$html .= "<table>";
foreach my $name (sort keys %mfs) {
my ($link,$r);
foreach my $chr (keys %{$mfs{$name}}) {
my $cs = $mfs{$name}->{$chr}[0]{'cs'};
$link .= qq(<td><strong>$cs $chr:</strong></td>);
foreach my $det (@{$mfs{$name}->{$chr}}) {
$link .= "<td>".$det->{'start'}.'-'.$det->{'end'}."</td>";
$r = "$chr:".$det->{'start'}.'-'.$det->{'end'};
}
}
$html .= sprintf(qq(<tr><td><a href="/%s/Location/Marker?m=%s;r=%s">%s</a></td>%s</tr>),
$species,
$name,
$r,
$name,
$link,
);
}
$html .= "</table>";
return $html;
}
#otherwise print details
else {
my $markers = [];
foreach my $mf (@$found_mf) {
push @{$markers}, $mf->marker;
}
return $self->render_marker_details($markers);
}
}
sub render_marker_details {
my $self = shift;
my ($markers) = @_;
my $object = $self->object;
my $species = $object->species;
my $html;
if (! @$markers) {
return qq(<h3>No markers found</h3>);
}
foreach my $m (@$markers) {
my $table = new EnsEMBL::Web::Document::HTML::TwoCol;
my $m_name = $m->display_MarkerSynonym ? $m->display_MarkerSynonym->name : '';
$html .= qq(<h3>Marker $m_name</h3>);
#location of marker features
my $loc_text = $self->render_location($m);
$table->add_row('Location',
$loc_text,
1);
#synonyms
if (my @important_syns = @{$self->markerSynonyms($m,1)}) {
my $syn_text;
foreach my $syn (@important_syns){
my $db = $syn->source;
my $id = $syn->name;
my $url = $object->get_ExtURL($db, $id) ;
$id = sprintf( qq(<a href="%s">%s</a>), $url, $id) if $url;
$syn_text .= qq(<table><tr><td>$id ($db)</td></tr></table>);
}
$table->add_row('Source',
$syn_text,
1);
}
#other synonyms (rows of $max_cols entries)
if (my @other_syns = @{$self->markerSynonyms($m,0)}) {
my $max_cols = 8;
my $syn_dbs;
foreach my $syn (@other_syns) {
my $db_name = $syn->source;
push @{$syn_dbs->{$db_name}},$syn->name;
}
my $other_syn_text = qq(<table><tr>);
foreach my $db (keys %{$syn_dbs}) {
my $c = 0;
$other_syn_text .= qq(<td><strong>$db:</strong></td>);
foreach my $id (@{$syn_dbs->{$db}}) {
my $url = $object->get_ExtURL_link( $id, uc($db), $id);
if ($c < $max_cols) {
$other_syn_text .= qq(<td>$url</td>);
$c++;
}
else {
$other_syn_text .= qq(</tr>
<tr><td></td><td>$url</td>);
$c = 1;
}
}
$other_syn_text .= qq(</tr>);
}
$other_syn_text .= qq(</table>);
$table->add_row('Synonyms',
$other_syn_text,
1);
}
#primer details
my $l = $m->left_primer;
my $r = $m->right_primer;
my $min_psize = $m->min_primer_dist;
my $max_psize = $m->max_primer_dist;
my $product_size;
if (!$min_psize) {
$product_size = " ";
}
elsif ($min_psize == $max_psize) {
$product_size = "$min_psize";
}
else {
$product_size = "$min_psize - $max_psize";
}
my $primer_txt;
if ($r) {
$l =~ s/([\.\w]{30})/$1<br \/>/g;
$r =~ s/([\.\w]{30})/$1<br \/>/g;
$primer_txt .= qq(<table>
<tr><td><strong>Expected Product Size:</strong></td><td>$product_size</td></tr>
<tr><td><strong>Left Primer:</strong></td><td>$l</td></tr>
<tr><td><strong>Right Primer:</strong></td><td>$r</td></tr>
</table>);
}
else {
$primer_txt = qq(Marker $m_name primers are not in the database);
}
$table->add_row('Primers',
$primer_txt,
1);
$html .= $table->render;
if (my @mml = @{$m->get_all_MapLocations()}) {
my $map_table = new EnsEMBL::Web::Document::SpreadSheet( [], [], {'margin' => '1em 0px'} );
$map_table->add_columns({ 'key' => 'map', 'align'=>'left', 'title' => 'Map Name'});
$map_table->add_columns({ 'key' => 'syn', 'align'=>'left', 'title' => 'Synonym' });
$map_table->add_columns({ 'key' => 'chr', 'align'=>'left', 'title' => 'Chromosome' });
$map_table->add_columns({ 'key' => 'pos', 'align'=>'left', 'title' => 'Position' });
$map_table->add_columns({ 'key' => 'lod', 'align'=>'left', 'title' => 'LOD Score' });
foreach my $ml (@mml) {
my $row = {'map' => $ml->map_name,
'syn' => $ml->name || '-',
'chr' => $ml->chromosome_name || ' ' ,
'pos' => $ml->position || '-',
'lod' => $ml->lod_score || '-',
'_raw' => $ml,};
$map_table->add_row($row);
}
$html .= $map_table->render;
}
}
return $html;
}
sub markerSynonyms {
my $self = shift;
my $m = shift;
my $important = shift;
my $syns = [];
my %IS_IMPORTANT = map { $_, 1 } qw( rgd oxford unists mgi:markersymbol );
foreach my $ms ( @{ $m->get_all_MarkerSynonyms } ) {
if ($important) {
push @{$syns}, $ms if $IS_IMPORTANT{ lc($ms->source) };
}
else {
push @{$syns}, $ms unless $IS_IMPORTANT{ lc($ms->source) };
}
}
return $syns;
}
sub render_location {
my $self = shift;
my $m = shift;
my $m_name = $m->display_MarkerSynonym ? $m->display_MarkerSynonym->name : '';
my $object = $self->object;
my $species = $object->species;
my $sitetype = $object->species_defs->ENSEMBL_SITETYPE;
my $mfs;
my $c = ($mfs = $m->get_all_MarkerFeatures) ? scalar(@$mfs) : 0;
my $loc_text = qq(<table>);
if ($c) {
if ($c > 1) {
my $extra = ($c > $MAP_WEIGHT) ? ' (note that for clarity markers mapped more than twice are not shown on location based views)' : '';
$loc_text .= sprintf (qq(<tr><td>%s is currently mapped to %d different %s locations%s%s%s</td></tr>),
$m_name,
$c,
$sitetype,
$extra,
( $c > $MAX_MAP_WEIGHT ? '.' : ':' ),
);
}
foreach my $mf (@$mfs){
my $sr_name = $mf->seq_region_name;
my $start = $mf->start;
my $end = $mf->end;
my $url = sprintf(qq(<a href="%s">%s:%d-%d</a>),
"/$species/Location/View?r=$sr_name:$start-$end;h=$m_name",
$sr_name,
$start,
$end,
);
my $extra;
if ($m->priority < $PRIORITY) {
$extra = qq([Note that for reasons of clarity this marker is not shown on 'Region in detail']);
}
$loc_text .= sprintf (qq(<tr><td>%s%s %s %s</td></tr>),
($c > 1) ? ' ' : '',
$mf->coord_system_name,
$url,
$extra);
}
}
else {
$loc_text .= qq(<tr><td>Marker $m_name is not mapped to the assembly in the current $sitetype database</td></tr>);
}
$loc_text .= qq(</table>);
return $loc_text;
}
1;