#!/usr/bin/perl -w # motifsearch.pl # finds user-specified motifs in a FASTA genome sequence # v 0.2 #0.1 basic working code #0.2 added gui use strict; use Bio::SeqIO; use Tk; use Tk::Label; use Tk::Button; use Tk::Checkbutton; use Tk::Frame; use Tk::Entry; use Tk::Radiobutton; use Tk::Scale; use Tk::Scrollbar; use Tk::Text; use Tk::ErrorDialog; use Tk::ProgressBar; use Tk::Balloon; use Tk::ROText; use Tk::NoteBook; use Tk::ErrorDialog; &lackgui; sub lackgui { my $mw = MainWindow->new(-title=>'Motif Search 0.2'); my $inputfr = $mw->Frame(-relief=>'groove', -borderwidth=>2, )->pack(-side=>'top', -anchor=>'nw', -fill=>'both', ); my $seqfile_label = $inputfr->Label(-text=>'Sequence File', )->grid(-row=>0,-column=> 0,-sticky=>'e'); my $seqfile; my $seqfile_e = $inputfr->Entry(-state=>'normal', -textvariable=> \$seqfile, -width=>30, )->grid(-row=>0,-column=> 1,-sticky=>'w'); $inputfr->Button(-text=>'Browse', -command=> [ \&selectsinglefile, \$seqfile_e , \$mw ], -borderwidth=>1, -padx=> 0, -pady=> 0, )->grid(-row=>0,-column=> 2,-sticky=>'w'); my $full_label =$inputfr->Label(-text=>'Motif', )->grid(-row=>1,-column=> 0,-sticky=>'e'); my $motif; my $motif_e = $inputfr->Entry(-state=>'normal', -textvariable=> \$motif, -width=>30, )->grid(-row=>1,-column=> 1,-sticky=>'w'); my $baseabbr1 = <Label(-text=>$baseabbr1, )->grid(-row=>2,-column=>0); $inputfr->Label(-text=>$baseabbr2, )->grid(-row=>2,-column=>1); $inputfr->Label(-text=>$baseabbr3, )->grid(-row=>2,-column=>2); my $buffer_label = $inputfr->Label(-text=>'Sequence buffer size', )->grid(-row=>3,-column=> 0,-sticky=>'e'); my $buffer = 10; my $datafile_e = $inputfr->Entry(-state=>'normal', -textvariable=> \$buffer, -width=>30, )->grid(-row=>3,-column=> 1,-sticky=>'w'); # log window my $log_f = $mw->Frame(-relief=>'groove', -borderwidth=>2, )->pack(-fill=>'both', -expand=>1); my $logwin = $log_f->Scrolled("Text")->pack(-fill=>'both', -expand=>1); $logwin->configure(-height=>20, -width=>80, -wrap=>'none', -state=>'disabled', ); # text options my $command_f = $mw->Frame(-relief=>'groove', -borderwidth=>2, )->pack(-fill=>'x'); $command_f->Button(-text=>"Save Results", -command=> [ \&saveresults,\$mw,\$logwin ], -state=> 'normal', )->grid(-row=>0, -column=>1, -padx=>20, ); my $statusb = $mw->ROText(-height=>1, -width=>30, -wrap=>'word', -relief=>'flat', -border=>0, )->pack(-side=>'left', -anchor=>'sw'); if ($^O =~ /mswin/i) { $statusb->configure(-background=>'SystemButtonFace'); } else { $statusb->configure(-background=>'grey'); } $statusb->insert('end','Idle'); $command_f->Button(-text=>"Find Motifs", -command=> [ \&main,\$seqfile,\$motif,\$buffer,\$logwin,\$statusb,\$mw ], -state=> 'normal', )->grid(-row=>0, -column=>0, -padx=>20, ); $command_f->Button(-text=>"Clear Results", -command=> sub { $logwin->configure(-state=>'normal'); $logwin->delete('1.0','end'); $logwin->configure(-state=>'disabled'); }, )->grid(-row=>0, -column=>2, -padx=>20, ); $command_f->Button(-text=>"Exit", -command=> sub { exit }, )->grid(-row=>0, -column=>3, -padx=>20, ); MainLoop; } # SUBROUTINES # sub printlog { my $line = shift; my $logwinref = shift; my $logwin = $$logwinref; $logwin->configure(-state=>'normal'); $logwin->insert('end',$line); $logwin->yview(moveto=>1); $logwin->configure(-state=>'disabled'); $logwin->update(); } sub saveresults { my $mwref = shift; my $mw = $$mwref; my $logwinref = shift; # fix portability my $outfile = $mw->getSaveFile(-title=>'Save Results As'); open(OUTFILE,">$outfile") or die "Can't open output file $outfile\n"; print OUTFILE $$logwinref->get("1.0","end"); close OUTFILE; $mw->messageBox(-title => 'Finished', -message => 'Results Saved', -type => 'OK'); } sub selectsinglefile { my $entryblankref = shift; my $entryblank = $$entryblankref; my $mwref = shift; my $mw = $$mwref; my $file; if ($^O =~ /mswin/i) { my $opentypes = [ "{All files} * ", "{PCL files} {.pcl} ", "{Text files} {.txt} ", ]; $file = $mw->getOpenFile(-filetypes=>$opentypes); } else { $file = $mw->getOpenFile(-title=>'Load File'); } if (defined $file and $file ne '') { $entryblank->delete(0, 'end'); $entryblank->insert(0, $file); $entryblank->xview('end'); } } sub main { my $seqfileref = shift; my $seqfile = $$seqfileref; my $motifref = shift; my $motif = $$motifref; my $motifbufferref = shift; my $motifbuffer = $$motifbufferref; my $logwinref = shift; my $statusbref = shift; my $mwref = shift; my $mw = $$mwref; if (!$seqfile) { $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Error'); die "No sequence file specified\n"; return; } if (!$motif) { $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Error'); die "No motif specified\n"; return; } if (!$motifbuffer) { $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Error'); die "No motif buffer specified\n"; return; } $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Formatting motifs'); $mw->update; my $motiff = $motif; $motiff = &match_form($motiff); my $motifr = $motif; $motifr = &revcom($motifr); $motifr = &match_form($motifr); my $buffer = '.' x $motifbuffer; $motiff = $buffer . $motiff . $buffer; $motifr = $buffer . $motifr . $buffer; &printlog("Search patterns\n",$logwinref); &printlog("---------------\n",$logwinref); &printlog("forward: $motiff\nreverse: $motifr\n\n",$logwinref); $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Reading sequence'); $mw->update; my $seqfileobj = Bio::SeqIO->new(-file => $seqfile, -format => 'fasta' ); $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Finding motifs'); $mw->update; while ( my $seqobj = $seqfileobj->next_seq() ) { my $seq = $seqobj->seq; my $desc = $seqobj->desc; &printlog("$desc\n",$logwinref); &printlog("\tforward\n",$logwinref); while ($seq =~ /($motiff)/gi) { my $position = pos($seq); my $match = $1; &printlog("\t\t$position\t$match\n",$logwinref); } &printlog("\treverse\n",$logwinref); while ($seq =~ /($motifr)/gi) { my $position = pos($seq); my $match = $1; &printlog("\t\t$position\t$match\n",$logwinref); } } &printlog("\n",$logwinref); $$statusbref->delete('1.0','end'); $$statusbref->insert('end','Analysis complete'); $mw->update; } sub match_form { my $motif = shift; $motif =~ s/r/\[ga\]/gi; $motif =~ s/y/\[tc\]/gi; $motif =~ s/k/\[gt\]/gi; $motif =~ s/m/\[ac\]/gi; $motif =~ s/s/\[gc\]/gi; $motif =~ s/w/\[at\]/gi; $motif =~ s/b/\[gtc\]/gi; $motif =~ s/d/\[gat\]/gi; $motif =~ s/h/\[atc\]/gi; $motif =~ s/v/\[gac\]/gi; $motif =~ s/n/\[gact\]/gi; return $motif; } sub revcom { my $oligo = shift; $oligo =~ tr/gatcGATC/ctagCTAG/; $oligo =~ tr/rykmbdhvRYKMBDHV/yrmkvhdbYRMKVHDB/; my $rcoligo = reverse($oligo); return $rcoligo; }