<commit_before>=head1 LICENSE

Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut

package EnsEMBL::Draw::Role::Bam;

### Module for drawing data in BAM or CRAM format (either user-attached,
### or internally configured via an ini file or database record
### Note: uses Inline C for faster handling of these huge files

### Note also that because of the file size, we do not use standard
### ensembl-io parsers with an IOWrapper module, but instead use an 
### adaptor and then munge the data here

use strict;

use Role::Tiny;

use Bio::EnsEMBL::DBSQL::DataFileAdaptor;
use Bio::EnsEMBL::IO::Adaptor::HTSAdaptor;

############# RENDERING ########################

sub render_coverage_with_reads {
### Standard rendering style 
  my $self = shift;
  $self->_render({'coverage' => 1, 'reads' => 1});
}

sub render_unlimited {
### 'External' rendering style
### Coverage and reads
  my $self = shift;
  $self->_render({'coverage' => 1, 'reads' => 1});
  $self->{'my_config'}->set('max_depth', 500);
}

sub render_histogram {
### 'External' rendering style
### Coverage only - no reads
  my $self = shift;
  $self->_render({'coverage' => 1, 'reads' => 0});
}

sub render_text {
### Text export
  my $self = shift;
  warn 'No text render implemented for bam';
  return '';
}

sub _render_coverage {
### Draw the coverage subtrack, using Style modules
  my $self = shift;

  ## Process the data using Inline C
  my @coverage = @{$self->calc_coverage};

  my $max = (sort {$b <=> $a} @coverage)[0];
  return if $max == 0; ## nothing to show

  ## Some useful stuff, mainly to do with rendering differently at different scales
  my $slice         = $self->{'container'};
  my $slice_start   = $slice->start;
  my $smax          = 100; ## Cutoff for values
  my $scale         = 3;
  my $pix_per_bp    = $self->scalex;

  ## Set some defaults for this graph
  my $default_colour = $self->my_colour('consensus');
  $self->{'my_config'}->set('axis_colour', $default_colour);
  $self->{'my_config'}->set('height', int($smax/$scale));
  $self->{'my_config'}->set('no_guidelines', 1);
  $self->{'my_config'}->set('baseline_zero', 1);
  $self->{'my_config'}->set('subtitle_y', -4);

  ## Do we want to show the consensus base? (ACTG)
  my $consensus;
  if ($pix_per_bp > 1) {
    $consensus = $self->consensus_features;
    $self->{'my_config'}->set('label_overlay', 1);
    $self->{'my_config'}->set('hide_subtitle', 1);
  }
  elsif ($pix_per_bp < 1) {
    ## Graph won't draw without this. Because reasons.
    $self->{'my_config'}->set('absolutex', 1);
  }

  my ($min_score,$max_score);
  my $viewLimits = $self->my_config('viewLimits');
  if ($viewLimits) {
    ($min_score,$max_score) = split ":",$viewLimits;
    $max = $max_score;
  }

  ## Munge into a format suitable for the Style module
  my $default_strand = $self->{'my_config'}->get('default_strand');
  my $name = $self->{'my_config'}->get('short_name') || $self->{'my_config'}->get('name');
  my $data = {'features' => [], 
              'metadata' => {
                             'name'      => $name,
                             'colour'    => $default_colour,
                             'max_score' => $max, 
                             'min_score' => $min_score || 0
                             }
              };

  my %config                = %{$self->track_style_config};
  $config{'pix_per_score'}  = $smax / ($scale * $max); 
  $config{'line_score'}     = 0;
  $config{'cutoff'}         = $smax;

  foreach my $i (0..$#coverage) {
    my $cvrg = $coverage[$i];
    my $cons = $consensus->{$slice_start + $i};

    my ($colour, $label);
    if ($pix_per_bp < 1 || !$cons) {
      $colour =  $default_colour;
    } else {
      $label  = $cons;
      $colour = $self->my_colour(lc($cons));
    }

    my $start = $i + 1;

    my $title = 'Coverage' .
                  "; Location: ".sprintf('%s:%s-%s',  $slice->seq_region_name, 
                                                      $start + $slice_start, 
                                                      $start + $slice_start) .
                  "; Score: $cvrg";

    my $hash = {
                  'start'   => $start,
                  'end'     => $start,
                  'score'   => $cvrg,
                  'label'   => $label,
                  'colour'  => $colour,
                  'title'   => $title,
                };
    
    push @{$data->{'features'}}, $hash;
  }
  #use Data::Dumper; warn Dumper($data);

  ## Draw coverage track
  my $style_class = 'EnsEMBL::Draw::Style::Graph::Bar';
  if ($self->dynamic_use($style_class)) {
    my $style = $style_class->new(\%config, [$data]);
    $self->push($style->create_glyphs);
  }

  ## This is clunky, but it's the only way we can make the new code
  ## work in a nice backwards-compatible way right now!
  ## Get label position, which is set in Style::Graph
  $self->{'label_y_offset'} = $self->{'my_config'}->get('label_y_offset');

  ## Everything went OK, so no error to return
  return 0;
}

sub _render_reads {
### Draw the reads subtrack, using Style modules
  my $self = shift;

  ## Establish defaults
  my $max_depth   = $self->my_config('max_depth') || 50;
  my $pix_per_bp  = $self->scalex; # pixels per base pair
  my $slice       = $self->{'container'};
  my $slicestart  = $slice->start;
  my $sliceend    = $slice->end;
  my $slicelength = $slice->length;
  my $slicestrand = $slice->strand;
  my $read_colour = $self->my_colour('read');
  $self->{'my_config'}->set('insert_colour', $self->my_colour('read_insert'));
<commit_msg>Helps if you set the track depth _before_ rendering it<commit_after>=head1 LICENSE

Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut

package EnsEMBL::Draw::Role::Bam;

### Module for drawing data in BAM or CRAM format (either user-attached,
### or internally configured via an ini file or database record
### Note: uses Inline C for faster handling of these huge files

### Note also that because of the file size, we do not use standard
### ensembl-io parsers with an IOWrapper module, but instead use an 
### adaptor and then munge the data here

use strict;

use Role::Tiny;

use Bio::EnsEMBL::DBSQL::DataFileAdaptor;
use Bio::EnsEMBL::IO::Adaptor::HTSAdaptor;

############# RENDERING ########################

sub render_coverage_with_reads {
### Standard rendering style 
  my $self = shift;
  $self->_render({'coverage' => 1, 'reads' => 1});
}

sub render_unlimited {
### 'External' rendering style
### Coverage and reads
  my $self = shift;
  $self->{'my_config'}->set('depth', 500);
  $self->_render({'coverage' => 1, 'reads' => 1});
}

sub render_histogram {
### 'External' rendering style
### Coverage only - no reads
  my $self = shift;
  $self->_render({'coverage' => 1, 'reads' => 0});
}

sub render_text {
### Text export
  my $self = shift;
  warn 'No text render implemented for bam';
  return '';
}

sub _render_coverage {
### Draw the coverage subtrack, using Style modules
  my $self = shift;

  ## Process the data using Inline C
  my @coverage = @{$self->calc_coverage};

  my $max = (sort {$b <=> $a} @coverage)[0];
  return if $max == 0; ## nothing to show

  ## Some useful stuff, mainly to do with rendering differently at different scales
  my $slice         = $self->{'container'};
  my $slice_start   = $slice->start;
  my $smax          = 100; ## Cutoff for values
  my $scale         = 3;
  my $pix_per_bp    = $self->scalex;

  ## Set some defaults for this graph
  my $default_colour = $self->my_colour('consensus');
  $self->{'my_config'}->set('axis_colour', $default_colour);
  $self->{'my_config'}->set('height', int($smax/$scale));
  $self->{'my_config'}->set('no_guidelines', 1);
  $self->{'my_config'}->set('baseline_zero', 1);
  $self->{'my_config'}->set('subtitle_y', -4);

  ## Do we want to show the consensus base? (ACTG)
  my $consensus;
  if ($pix_per_bp > 1) {
    $consensus = $self->consensus_features;
    $self->{'my_config'}->set('label_overlay', 1);
    $self->{'my_config'}->set('hide_subtitle', 1);
  }
  elsif ($pix_per_bp < 1) {
    ## Graph won't draw without this. Because reasons.
    $self->{'my_config'}->set('absolutex', 1);
  }

  my ($min_score,$max_score);
  my $viewLimits = $self->my_config('viewLimits');
  if ($viewLimits) {
    ($min_score,$max_score) = split ":",$viewLimits;
    $max = $max_score;
  }

  ## Munge into a format suitable for the Style module
  my $default_strand = $self->{'my_config'}->get('default_strand');
  my $name = $self->{'my_config'}->get('short_name') || $self->{'my_config'}->get('name');
  my $data = {'features' => [], 
              'metadata' => {
                             'name'      => $name,
                             'colour'    => $default_colour,
                             'max_score' => $max, 
                             'min_score' => $min_score || 0
                             }
              };

  my %config                = %{$self->track_style_config};
  $config{'pix_per_score'}  = $smax / ($scale * $max); 
  $config{'line_score'}     = 0;
  $config{'cutoff'}         = $smax;

  foreach my $i (0..$#coverage) {
    my $cvrg = $coverage[$i];
    my $cons = $consensus->{$slice_start + $i};

    my ($colour, $label);
    if ($pix_per_bp < 1 || !$cons) {
      $colour =  $default_colour;
    } else {
      $label  = $cons;
      $colour = $self->my_colour(lc($cons));
    }

    my $start = $i + 1;

    my $title = 'Coverage' .
                  "; Location: ".sprintf('%s:%s-%s',  $slice->seq_region_name, 
                                                      $start + $slice_start, 
                                                      $start + $slice_start) .
                  "; Score: $cvrg";

    my $hash = {
                  'start'   => $start,
                  'end'     => $start,
                  'score'   => $cvrg,
                  'label'   => $label,
                  'colour'  => $colour,
                  'title'   => $title,
                };
    
    push @{$data->{'features'}}, $hash;
  }
  #use Data::Dumper; warn Dumper($data);

  ## Draw coverage track
  my $style_class = 'EnsEMBL::Draw::Style::Graph::Bar';
  if ($self->dynamic_use($style_class)) {
    my $style = $style_class->new(\%config, [$data]);
    $self->push($style->create_glyphs);
  }

  ## This is clunky, but it's the only way we can make the new code
  ## work in a nice backwards-compatible way right now!
  ## Get label position, which is set in Style::Graph
  $self->{'label_y_offset'} = $self->{'my_config'}->get('label_y_offset');

  ## Everything went OK, so no error to return
  return 0;
}

sub _render_reads {
### Draw the reads subtrack, using Style modules
  my $self = shift;

  ## Establish defaults
  my $max_depth   = $self->my_config('depth') || 50;
  my $pix_per_bp  = $self->scalex; # pixels per base pair
  my $slice       = $self->{'container'};
  my $slicestart  = $slice->start;
  my $sliceend    = $slice->end;
  my $slicelength = $slice->length;
  my $slicestrand = $slice->strand;
  my $read_colour = $self->my_colour('read');
  $self->{'my_config'}->set('insert_colour', $self->my_colour('read_insert'));

{'fraction_non_alphanumeric': 0.16260692464358453, 'fraction_numerical': 0.0071690427698574335, 'mean_word_length': 2.805331680099194, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 157, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7535701', 'n_tokens_mistral': 4123, 'n_tokens_neox': 3896, 'n_words': 1117}