Bio-Graphics
view release on metacpan or search on metacpan
lib/Bio/Graphics/Glyph/trace.pm view on Meta::CPAN
use File::Temp qw( tempdir );
use Digest::MD5 qw( md5_hex );
use base 'Bio::Graphics::Glyph::generic';
our @ISA;
use constant VERTICAL_SPACING => 20;
my %complement = (
g => 'c',
a => 't',
t => 'a',
c => 'g',
n => 'n',
G => 'C',
A => 'T',
T => 'A',
C => 'G',
N => 'N'
);
sub new {
my $self = shift->SUPER::new(@_);
if ( $self->dna_fits ) {
$self->{parsed_trace} = $self->get_parsed_trace();
}
return $self;
}
sub get_parsed_trace {
my $self = shift;
my ( $format, $trace_file ) = eval { $self->trace_data };
unless ($trace_file) {
warn $@ if $@;
return;
}
if ($self->{'content_type'} eq "ABI"){
require ABI;
my $abi = ABI->new(-file=>$trace_file);
my %scf;
@{$scf{'bases'}} = split //, $abi->get_sequence();
@{$scf{'index'}} = $abi->get_base_calls();
@{$scf{'samples'}{'A'}} = $abi->get_trace('A');
@{$scf{'samples'}{'C'}} = $abi->get_trace('C');
@{$scf{'samples'}{'G'}} = $abi->get_trace('G');
@{$scf{'samples'}{'T'}} = $abi->get_trace('T');
my $scale_factor = $self->option('abi_scale') || 1;
$self->{'max_trace'} = $scale_factor * $abi->get_max_trace();
return \%scf;
}
else{
my %scf;
tie %scf, 'Bio::SCF', $trace_file;
$self->{'max_trace'} = 1600;
return \%scf;
}
}
sub _guess_format {
my $self = shift;
my $path = shift;
my $modded_path = $path;
$self->{'gzipped'} = ($modded_path =~ s/\.gz\s*$// );
if ($modded_path =~ /\.scf/){
$self->{'content_type'} = 'Bio::SCF';
}
elsif ($modded_path =~ /\.ab1/){
$self->{'content_type'} = 'ABI';
}
else{
die "$path: Trace file not of recognized format\n"
}
return;
}
sub trace_path {
my $self = shift;
my $feature = $self->feature or die "no feature!";
my $dirname = $self->trace_dir;
my $basename = $self->option('trace');
# can't get it from callback, so try looking for an 'trace' attribute
if ( !$basename ) {
if ( $feature->can('attributes') ) {
($basename) = $feature->attributes('trace');
}
elsif ( $feature->can('has_tag') && $feature->has_tag('trace') ) {
($basename) = $feature->get_tag_values('trace');
}
}
return unless $basename;
return $basename if $basename =~ m!^\w+:/!; # looks like a URL
return $basename if $basename =~ m!^/!; # looks like an abs path
return "$dirname/$basename";
}
sub trace_data {
my $self = shift;
my $path = $self->trace_path;
$self->_guess_format($path);
if ( $path =~ m!^\w+:/! ) { # looks like a URL
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $response = $ua->get($path);
if ( $response->is_success ) {
# In the future, make extensible to ABI format
my $data = $response->content;
my $signature = md5_hex($data);
my $extension;
if ($self->{'content_type'} eq 'ABI'){
$extension = 'ab1';
}
else{
$extension = 'scf';
}
if ($self->{'gzipped'}){
$extension .= '.gz';
}
# untaint signature for use in open
$signature =~ /^([0-9A-Fa-f]+)$/g or return;
$signature = $1;
my $dir_path = tempdir();
my $file_name
= sprintf( "%s/%s.%s", $dir_path, $signature, $extension );
open( F, ">$file_name" )
|| die("Can't open file $file_name for writing: $!\n");
binmode(F);
print F $data;
close F;
if ($self->{'gzipped'}){
$file_name = $self->gunzip_file( $file_name );
}
return ( $self->{'content_type'}, $file_name );
}
else {
die $response->status_line;
}
}
else {
if ($self->{'gzipped'}){
$path = $self->gunzip_file( $path );
}
return ( $self->{'content_type'}, $path );
}
}
sub gunzip_file {
my $self = shift;
my $file_name = shift;
$file_name =~ /(.+)\.gz$/;
my $new_file_name = $1;
( run in 1.254 second using v1.01-cache-2.11-cpan-39bf76dae61 )