/usr/bin/bp_mask_by_search is in bioperl 1.7.1-2.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | #!/usr/bin/perl
# Author: Jason Stajich <jason-at-bioperl-dot-org>
=head1 NAME
bp_mask_by_search - mask sequence(s) based on its alignment results
=head1 SYNOPSIS
bp_mask_by_search.pl -f blast genomefile blastfile.bls > maskedgenome.fa
=head1 DESCRIPTION
Mask sequence based on significant alignments of another sequence.
You need to provide the report file and the entire sequence data which
you want to mask. By default this will assume you have done a TBLASTN
(or TFASTY) and try and mask the hit sequence assuming you've provided
the sequence file for the hit database. If you would like to do the
reverse and mask the query sequence specify the -t/--type query flag.
This is going to read in the whole sequence file into memory so for
large genomes this may fall over. I'm using DB_File to prevent
keeping everything in memory, one solution is to split the genome into
pieces (BEFORE you run the DB search though, you want to use the exact
file you BLASTed with as input to this program).
Below the double dash (--) options are of the form
--format=fasta or --format fasta
or you can just say
-f fasta
By -f/--format I mean either are acceptable options. The =s or =n
or =c specify these arguments expect a 'string'
Options:
-f/--format=s Search report format (fasta,blast,axt,hmmer,etc)
-sf/--sformat=s Sequence format (fasta,genbank,embl,swissprot)
--hardmask (booelean) Hard mask the sequence
with the maskchar [default is lowercase mask]
--maskchar=c Character to mask with [default is N], change
to 'X' for protein sequences
-e/--evalue=n Evalue cutoff for HSPs and Hits, only
mask sequence if alignment has specified evalue
or better
-o/--out/
--outfile=file Output file to save the masked sequence to.
-t/--type=s Alignment seq type you want to mask, the
'hit' or the 'query' sequence. [default is 'hit']
--minlen=n Minimum length of an HSP for it to be used
in masking [default 0]
-h/--help See this help information
=head1 AUTHOR - Jason Stajich
Jason Stajich, jason-at-bioperl-dot-org.
=cut
use strict;
use warnings;
use Bio::SeqIO;
use Bio::SearchIO;
use Getopt::Long;
use Bio::Seq;
use DB_File;
# assuming tblastn or tfasty type alignment
my $format = 'blast';
my $sformat= undef;
my $evalue = undef;
my $type = 'hit';
my $minlen = 50;
my $hardmask = 0; # mask with $maskchar instead of lowercase
my $maskchar = 'N'; # if we hard mask, mask with this cahr
my $outfile;
GetOptions(
'f|format:s' => \$format,
'sf|sformat:s'=> \$sformat,
'hardmask' => \$hardmask,
'maskchar:s' => \$maskchar,
'e|evalue:s' => \$evalue,
'o|out|outfile:s' => \$outfile,
't|type:s' => \$type,
'minlen:s' => \$minlen,
'h|help' => sub { system('perldoc', $0);
exit; },
);
if( $type !~ /^(hit|query)/i ) {
die("type must be query or hit[default] not $type") ;
}
$type = lc($type);
if(length($maskchar) > 1 ) {
die("expected a mask character, not a string (you gave $maskchar)");
}
my $genomefile = shift || die('need a file containing the genome');
my $reportfile = shift;
# this could be problem for large genomes, figure out a
# better way to do this later on
# or force people to split it up
my $genomeparser = new Bio::SeqIO(-file => $genomefile,
-format=> $sformat);
my %seqs;
unlink('/tmp/genome.idx');
tie(%seqs,'DB_File','/tmp/genome.idx');
while( my $seq = $genomeparser->next_seq ) {
# should we pre-force to upper case?
$seqs{$seq->display_id} = $seq->seq();
}
my $parser = new Bio::SearchIO(-file => $reportfile,
-format => $format);
while( my $r = $parser->next_result ) {
while( my $h = $r->next_hit ) {
last if( defined $evalue && $h->significance > $evalue );
my $hname = $h->name;
if( ! $seqs{$hname} ) {
die("Cannot find sequence $hname in genome seq");
}
while( my $hsp = $h->next_hsp ) {
last if( defined $evalue && $hsp->evalue > $evalue );
next if( $hsp->length('total') < $minlen);
my ($s,$len) = ( $hsp->$type()->start,
$hsp->$type()->length);
if( $hardmask ) {
substr($seqs{$hname}, $s,$len, $maskchar x $len);
} else {
substr($seqs{$hname}, $s,$len,
lc(substr($seqs{$hname}, $s,$len)));
}
}
}
}
my $out;
if( $outfile ) {
$out = new Bio::SeqIO(-file => ">$outfile",
-format => $sformat);
} else {
$out = new Bio::SeqIO(-format => $sformat);
}
while( my ($seqname,$seq) = each %seqs ) {
$out->write_seq(Bio::Seq->new(-seq => $seq,
-display_id => $seqname,
-description=> 'MASKED'));
}
END {
unlink('/tmp/genome.idx');
}
|