20251125
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use FindBin;
|
||||
use lib "$FindBin::RealBin/../../PerlLib";
|
||||
use Fasta_reader;
|
||||
use List::Util qw(min max);
|
||||
use Overlap_piler;
|
||||
use Data::Dumper;
|
||||
|
||||
my $usage = "\n\n\tusage: $0 blast.outfmt6 query_fasta target_fasta\n\n\n";
|
||||
|
||||
my $blast_file = $ARGV[0] or die $usage;
|
||||
my $query_fasta = $ARGV[1] or die $usage;
|
||||
my $target_fasta = $ARGV[2] or die $usage;
|
||||
|
||||
|
||||
my %query_seq_lens = &get_seq_lengths($query_fasta);
|
||||
|
||||
my %target_seq_lens;
|
||||
if ($query_fasta eq $target_fasta) {
|
||||
%target_seq_lens = %query_seq_lens;
|
||||
}
|
||||
else {
|
||||
%target_seq_lens = &get_seq_lengths($target_fasta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
my $MAX_MISSING = 10;
|
||||
my $COUNT_MISSING = 0;
|
||||
|
||||
main: {
|
||||
|
||||
# header
|
||||
print join("\t", "#query_acc", "target_acc", "avg_per_id", "min_Evalue",
|
||||
"query_match_range", "target_match_range", "pct_query_len", "pct_target_len", "max_pct_len") . "\n";
|
||||
|
||||
|
||||
my @hits;
|
||||
my $prev_query_target_pair = "";
|
||||
|
||||
open (my $fh, $blast_file) or die "Error, cannot open file $blast_file";
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
my @x = split(/\t/);
|
||||
my $query_acc = $x[0];
|
||||
my $target_acc = $x[1];
|
||||
|
||||
my $query_target_pair = join("$;", $query_acc, $target_acc);
|
||||
if ($query_target_pair ne $prev_query_target_pair) {
|
||||
&process_hits(@hits) if @hits;
|
||||
@hits = ();
|
||||
}
|
||||
push (@hits, [@x]);
|
||||
$prev_query_target_pair = $query_target_pair;
|
||||
}
|
||||
|
||||
# get last one
|
||||
&process_hits(@hits);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
####
|
||||
sub process_hits {
|
||||
my @hits = @_;
|
||||
|
||||
#print Dumper(\@hits);
|
||||
|
||||
my @query_coords;
|
||||
my @target_coords;
|
||||
|
||||
my $query_acc = "";
|
||||
my $target_acc = "";
|
||||
|
||||
my $sum_pct_id_len = 0;
|
||||
my $sum_len = 0;
|
||||
|
||||
my $min_evalue = 1;
|
||||
|
||||
foreach my $hit (@hits) {
|
||||
my @fields = @$hit;
|
||||
|
||||
unless ($query_acc) {
|
||||
$query_acc = $fields[0];
|
||||
$target_acc = $fields[1];
|
||||
}
|
||||
|
||||
my ($query_lend, $query_rend) = sort {$a<=>$b} ($fields[6], $fields[7]);
|
||||
my ($target_lend, $target_rend) = sort {$a<=>$b} ($fields[8], $fields[9]);
|
||||
|
||||
my $per_id = $fields[2];
|
||||
my $query_seg_len = $query_rend - $query_lend + 1;
|
||||
$sum_pct_id_len += $query_seg_len * $per_id;
|
||||
$sum_len += $query_seg_len;
|
||||
|
||||
my $evalue = $fields[10];
|
||||
if ($evalue < $min_evalue) {
|
||||
$min_evalue = $evalue;
|
||||
}
|
||||
|
||||
push (@query_coords, [$query_lend, $query_rend]);
|
||||
push (@target_coords, [$target_lend, $target_rend]);
|
||||
|
||||
}
|
||||
|
||||
my $avg_per_id = sprintf("%.2f", $sum_pct_id_len / $sum_len);
|
||||
|
||||
|
||||
my $query_match_len = 0;
|
||||
my @query_match_regions;
|
||||
{
|
||||
|
||||
my @query_piles = &Overlap_piler::simple_coordsets_collapser(@query_coords);
|
||||
foreach my $pile (@query_piles) {
|
||||
my ($pile_lend, $pile_rend) = @$pile;
|
||||
$query_match_len += $pile_rend - $pile_lend + 1;
|
||||
push (@query_match_regions, "$pile_lend-$pile_rend");
|
||||
}
|
||||
}
|
||||
|
||||
my $target_match_len = 0;
|
||||
my @target_match_regions;
|
||||
{
|
||||
my @target_piles = &Overlap_piler::simple_coordsets_collapser(@target_coords);
|
||||
foreach my $pile (@target_piles) {
|
||||
my ($pile_lend, $pile_rend) = @$pile;
|
||||
$target_match_len += $pile_rend - $pile_lend + 1;
|
||||
push (@target_match_regions, "$pile_lend-$pile_rend");
|
||||
}
|
||||
}
|
||||
|
||||
my $query_len = $query_seq_lens{$query_acc};
|
||||
my $target_len = $target_seq_lens{$target_acc};
|
||||
|
||||
if ( ! defined ($query_len)) {
|
||||
print STDERR "Error, missing length for query: [$query_acc]\n";
|
||||
$COUNT_MISSING++;
|
||||
if ($COUNT_MISSING > $MAX_MISSING) {
|
||||
die "Error, too many missing seq length entries encountered\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (! defined($target_len)) {
|
||||
print STDERR "Error, missing length for db hit: [$target_acc]\n";
|
||||
$COUNT_MISSING++;
|
||||
if ($COUNT_MISSING > $MAX_MISSING) {
|
||||
die "Error, too many missing seq length entries encountered\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
my $pct_query_len = sprintf("%.2f", $query_match_len / $query_len * 100);
|
||||
my $pct_target_len = sprintf("%.2f", $target_match_len / $target_len * 100);
|
||||
|
||||
|
||||
print join("\t", $query_acc, $target_acc, $avg_per_id, $min_evalue,
|
||||
join(",", @query_match_regions), join(",", @target_match_regions),
|
||||
$pct_query_len, $pct_target_len, max($pct_query_len, $pct_target_len) ) . "\n";
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
####
|
||||
sub get_seq_lengths {
|
||||
my ($fasta_file) = @_;
|
||||
|
||||
my %seq_lens;
|
||||
|
||||
my $fasta_reader = new Fasta_reader($fasta_file);
|
||||
while (my $seq_obj = $fasta_reader->next()) {
|
||||
|
||||
my $acc = $seq_obj->get_accession();
|
||||
my $seq_len = length($seq_obj->get_sequence());
|
||||
|
||||
# print STDERR "$acc => $seq_len\n";
|
||||
|
||||
$seq_lens{$acc} = $seq_len;
|
||||
}
|
||||
|
||||
return(%seq_lens);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user