Skip to content

Commit ea3e7e9

Browse files
Shaun Mahonyclaude
andcommitted
Add -webmode flag with structured stdout output and enhanced C++ output
Enhance STAMP binary to output detailed structured data for the web frontend: - Add -webmode flag: all results to stdout in >>STAMP_ delimited sections, no files written - Track reverse-complement state per motif via alignedRC with XOR propagation - Emit aligned PFMs with strand/offset info for proper aligned logo display - Output intermediate familial profiles at each internal tree node - Add Internal_N labels to Newick tree matching internal profiles - Remove legacy 20-char Phylip name truncation - Add strand tracking to similarity matching output - Default mode enhanced with new _enhanced_alignment.txt and _internal_profiles.txt files Also includes web frontend improvements: SequenceLogo rewrite, MatchTable/TreeViewer enhancements, MultipleAlignmentViewer component, STAMP output parser updates, and worker processor webmode integration. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 3b5ab17 commit ea3e7e9

File tree

22 files changed

+1061
-306
lines changed

22 files changed

+1061
-306
lines changed

src/Alignment.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,11 @@ MultiAlignRec::MultiAlignRec(int nA, int aL)
8282
alignL=aL;
8383
alignedNames = new char*[numAligned];
8484
alignedIDs = new int [numAligned];
85-
for(i=0; i<numAligned; i++)
85+
alignedRC = new bool[numAligned];
86+
for(i=0; i<numAligned; i++){
8687
alignedNames[i] = new char[STR_LEN];
88+
alignedRC[i] = false;
89+
}
8790
profileAlignment = new Motif*[numAligned];
8891
for(i=0; i<numAligned; i++){
8992
profileAlignment[i]=new Motif(alignL);

src/Alignment.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ class MultiAlignRec{
101101
Motif** profileAlignment;
102102
char** alignedNames;
103103
int* alignedIDs;
104+
bool* alignedRC; // Tracks whether each motif was reverse-complemented relative to input
104105

105106
//Constructor
106107
MultiAlignRec(int nA=2, int aL=0);
@@ -118,6 +119,7 @@ class MultiAlignRec{
118119
delete [] alignedNames[k];
119120
delete [] alignedNames;
120121
delete [] alignedIDs;
122+
delete [] alignedRC;
121123
}
122124
};
123125

src/MultipleAlignment.cpp

Lines changed: 154 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void MultipleAlignment::PrintMultipleAlignmentConsensus(MultiAlignRec* alignment
160160
{
161161
alignment = completeAlignment;
162162
if(alignment == NULL)
163-
{ printf("Error: complete alignment not yet constructed!\n\n");
163+
{ fprintf(stderr, "Error: complete alignment not yet constructed!\n\n");
164164
exit(1);
165165
}
166166
}
@@ -170,6 +170,8 @@ void MultipleAlignment::PrintMultipleAlignmentConsensus(MultiAlignRec* alignment
170170
int aL = alignment->GetAlignL();
171171

172172
if(aL>0){
173+
if(webMode)
174+
printf(">>STAMP_MULTI_ALIGN_CONSENSUS_START\n");
173175
if(htmlOutput)
174176
printf("<center><font face=\"Courier New\"><table border=\"0\" width=\"700\">");
175177
for(int q=0; q<alignment->GetNumAligned(); q++){
@@ -195,7 +197,8 @@ void MultipleAlignment::PrintMultipleAlignmentConsensus(MultiAlignRec* alignment
195197
printf("\n");
196198
if(htmlOutput)
197199
printf("</table></font></center>");
198-
200+
if(webMode)
201+
printf(">>STAMP_MULTI_ALIGN_CONSENSUS_END\n");
199202
}
200203
}
201204

@@ -260,11 +263,14 @@ MultiAlignRec* ProgressiveProfileAlignment::BuildAlignment(PlatformSupport* p, A
260263
//////////////////////////////////////////////////////////////////
261264
PrintMultipleAlignmentConsensus(T->root->alignment);
262265
strcpy(T->root->profile->name, "FBP");
263-
char outFName[STR_LEN];
264-
sprintf(outFName, "%sFBP.txt", outName);
265-
FILE* out=fopen(outFName, "w");
266-
T->root->profile->PrintMotif(out);
267-
fclose(out);
266+
// Only write FBP file when -out was provided (outName is non-empty)
267+
if(strlen(outName) > 0){
268+
char outFName[STR_LEN];
269+
sprintf(outFName, "%sFBP.txt", outName);
270+
FILE* out=fopen(outFName, "w");
271+
T->root->profile->PrintMotif(out);
272+
fclose(out);
273+
}
268274

269275
return(T->root->alignment);
270276
}
@@ -288,6 +294,7 @@ void ProgressiveProfileAlignment::PostorderAlignment(TreeNode* n, TreeNode* star
288294
strcpy(n->alignment->alignedNames[0], n->profile->name);
289295
strcpy(n->alignment->profileAlignment[0]->name, n->profile->name);
290296
n->alignment->alignedIDs[0] = n->leafID;
297+
n->alignment->alignedRC[0] = false; // Leaf is always in forward orientation
291298
//Fill alignSection
292299
for(z=0; z<n->profile->GetLen(); z++)
293300
for(b=0; b<B; b++)
@@ -320,10 +327,14 @@ void ProgressiveProfileAlignment::PostorderAlignment(TreeNode* n, TreeNode* star
320327
strcpy(n->alignment->alignedNames[b], n->left->alignment->alignedNames[b]);
321328
strcpy(n->alignment->profileAlignment[b]->name,n->left->alignment->alignedNames[b]);
322329
n->alignment->alignedIDs[b] = n->left->alignment->alignedIDs[b];
330+
// RC propagation: XOR child's RC state with whether this subtree was reversed
331+
n->alignment->alignedRC[b] = n->left->alignment->alignedRC[b] ^ (!forward1);
323332
}for(b=0; b<n->right->alignment->GetNumAligned(); b++){
324333
strcpy(n->alignment->alignedNames[b+n->left->alignment->GetNumAligned()], n->right->alignment->alignedNames[b]);
325334
strcpy(n->alignment->profileAlignment[b+n->left->alignment->GetNumAligned()]->name, n->right->alignment->alignedNames[b]);
326335
n->alignment->alignedIDs[b+n->left->alignment->GetNumAligned()] = n->right->alignment->alignedIDs[b];
336+
// RC propagation: XOR child's RC state with whether this subtree was reversed
337+
n->alignment->alignedRC[b+n->left->alignment->GetNumAligned()] = n->right->alignment->alignedRC[b] ^ (!forward2);
327338
}
328339
last0=-50; last1=-50;
329340
antiZ=0;
@@ -494,11 +505,14 @@ MultiAlignRec* IterativeRefinementAlignment::BuildAlignment(PlatformSupport* p,
494505
PrintMultipleAlignmentConsensus(alignment);
495506

496507
strcpy(currProfile->name, "FBP");
497-
char outFName[STR_LEN];
498-
sprintf(outFName, "%sFBP.txt", outName);
499-
FILE* out=fopen(outFName, "w");
500-
currProfile->PrintMotif(out);
501-
fclose(out);
508+
// Only write FBP file when -out was provided (outName is non-empty)
509+
if(strlen(outName) > 0){
510+
char outFName[STR_LEN];
511+
sprintf(outFName, "%sFBP.txt", outName);
512+
FILE* out=fopen(outFName, "w");
513+
currProfile->PrintMotif(out);
514+
fclose(out);
515+
}
502516

503517
if(currProfile!=NULL)
504518
delete currProfile;
@@ -538,10 +552,14 @@ MultiAlignRec* MultipleAlignment::SingleProfileAddition(MultiAlignRec* alignment
538552
strcpy(newAlignment->alignedNames[b], alignment->alignedNames[b]);
539553
strcpy(newAlignment->profileAlignment[b]->name, alignment->alignedNames[b]);
540554
newAlignment->alignedIDs[b] = alignment->alignedIDs[b];
555+
// RC propagation: XOR existing RC state with whether this alignment was reversed
556+
newAlignment->alignedRC[b] = alignment->alignedRC[b] ^ (!forward1);
541557
}
542558
strcpy(newAlignment->alignedNames[alignment->GetNumAligned()], two->name);
543559
strcpy(newAlignment->profileAlignment[alignment->GetNumAligned()]->name, two->name);
544560
newAlignment->alignedIDs[alignment->GetNumAligned()] = twoID;
561+
// The new motif's RC state: reverse-complemented if forward2 is false
562+
newAlignment->alignedRC[alignment->GetNumAligned()] = !forward2;
545563

546564
last0=-50; last1=-50;
547565
antiZ=0;
@@ -652,6 +670,7 @@ MultiAlignRec* MultipleAlignment::SingleProfileSubtraction(MultiAlignRec* alignm
652670
strcpy(newAlignment->alignedNames[a], alignment->alignedNames[i]);
653671
strcpy(newAlignment->profileAlignment[a]->name, alignment->alignedNames[i]);
654672
newAlignment->alignedIDs[a] = alignment->alignedIDs[i];
673+
newAlignment->alignedRC[a] = alignment->alignedRC[i]; // Copy RC state
655674
a++;
656675
}
657676
}
@@ -720,3 +739,126 @@ void MultipleAlignment::WeightedFBP(MultiAlignRec* alignment, Motif* currProfile
720739
Plat->n_to_pwm(currProfile);
721740
}
722741

742+
//Print enhanced alignment with strand, offset, and full PFM data to stdout (webmode)
743+
void MultipleAlignment::PrintEnhancedAlignment(MultiAlignRec* alignment)
744+
{
745+
if(alignment == NULL){
746+
alignment = completeAlignment;
747+
if(alignment == NULL){
748+
fprintf(stderr, "Error: complete alignment not yet constructed!\n");
749+
return;
750+
}
751+
}
752+
753+
int z, b;
754+
int aL = alignment->GetAlignL();
755+
756+
if(aL > 0){
757+
printf(">>STAMP_ENHANCED_ALIGNMENT_START\n");
758+
for(int q = 0; q < alignment->GetNumAligned(); q++){
759+
// Print motif header: name, strand (+/-), original ID
760+
printf(">>MOTIF\t%s\t%c\t%d\n",
761+
alignment->alignedNames[q],
762+
alignment->alignedRC[q] ? '-' : '+',
763+
alignment->alignedIDs[q]);
764+
765+
// Print consensus string
766+
printf(">>CONSENSUS\t");
767+
for(z = 0; z < aL; z++){
768+
if(alignment->profileAlignment[q]->f[z][0] == -1)
769+
printf("-");
770+
else
771+
printf("%c", alignment->profileAlignment[q]->ColConsensus(z));
772+
}
773+
printf("\n");
774+
775+
// Print full PFM
776+
printf(">>PFM_START\t%d\n", aL);
777+
for(z = 0; z < aL; z++){
778+
if(alignment->profileAlignment[q]->f[z][0] == -1){
779+
printf("GAP\n");
780+
}else{
781+
for(b = 0; b < B; b++){
782+
printf("%lf", alignment->profileAlignment[q]->f[z][b]);
783+
if(b < B-1) printf("\t");
784+
}
785+
printf("\n");
786+
}
787+
}
788+
printf(">>PFM_END\n");
789+
}
790+
printf(">>STAMP_ENHANCED_ALIGNMENT_END\n");
791+
}
792+
}
793+
794+
//Print FBP profile to stdout in delimited section (webmode)
795+
void MultipleAlignment::PrintFBPToStdout(Motif* fbp)
796+
{
797+
if(fbp == NULL) return;
798+
799+
int i, j;
800+
printf(">>STAMP_FBP_START\n");
801+
printf("DE\t%s\n", fbp->name);
802+
for(i = 0; i < fbp->len; i++){
803+
printf("%d\t", i);
804+
for(j = 0; j < B; j++)
805+
printf("%.4lf\t", fbp->f[i][j]);
806+
printf("%c\n", fbp->ColConsensus(i));
807+
}
808+
printf("XX\n");
809+
printf(">>STAMP_FBP_END\n");
810+
}
811+
812+
//Write enhanced alignment to file (default mode)
813+
void MultipleAlignment::WriteEnhancedAlignment(char* outPrefix, MultiAlignRec* alignment)
814+
{
815+
if(alignment == NULL){
816+
alignment = completeAlignment;
817+
if(alignment == NULL) return;
818+
}
819+
820+
int z, b;
821+
int aL = alignment->GetAlignL();
822+
if(aL <= 0) return;
823+
824+
char outFName[STR_LEN];
825+
sprintf(outFName, "%s_enhanced_alignment.txt", outPrefix);
826+
FILE* out = fopen(outFName, "w");
827+
if(out == NULL){
828+
fprintf(stderr, "Error: can't open output file %s\n", outFName);
829+
return;
830+
}
831+
832+
for(int q = 0; q < alignment->GetNumAligned(); q++){
833+
fprintf(out, ">>MOTIF\t%s\t%c\t%d\n",
834+
alignment->alignedNames[q],
835+
alignment->alignedRC[q] ? '-' : '+',
836+
alignment->alignedIDs[q]);
837+
838+
fprintf(out, ">>CONSENSUS\t");
839+
for(z = 0; z < aL; z++){
840+
if(alignment->profileAlignment[q]->f[z][0] == -1)
841+
fprintf(out, "-");
842+
else
843+
fprintf(out, "%c", alignment->profileAlignment[q]->ColConsensus(z));
844+
}
845+
fprintf(out, "\n");
846+
847+
fprintf(out, ">>PFM_START\t%d\n", aL);
848+
for(z = 0; z < aL; z++){
849+
if(alignment->profileAlignment[q]->f[z][0] == -1){
850+
fprintf(out, "GAP\n");
851+
}else{
852+
for(b = 0; b < B; b++){
853+
fprintf(out, "%lf", alignment->profileAlignment[q]->f[z][b]);
854+
if(b < B-1) fprintf(out, "\t");
855+
}
856+
fprintf(out, "\n");
857+
}
858+
}
859+
fprintf(out, ">>PFM_END\n");
860+
}
861+
862+
fclose(out);
863+
}
864+

src/MultipleAlignment.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,18 +50,22 @@ class MultipleAlignment{
5050
Alignment* A_man;
5151
MultiAlignRec* completeAlignment;
5252
bool htmlOutput;
53+
bool webMode;
5354
char outName[STR_LEN];
5455

5556
public:
5657
//Constructor
57-
MultipleAlignment(char* outRoot, bool html){completeAlignment=NULL; htmlOutput = html; strcpy(outName, outRoot);}
58+
MultipleAlignment(char* outRoot, bool html){completeAlignment=NULL; htmlOutput = html; webMode = false; strcpy(outName, outRoot);}
5859

5960
//Virtual building method
6061
virtual MultiAlignRec* BuildAlignment(PlatformSupport* p, Alignment* a, Tree* curr_tree=NULL)=0;
6162

6263
//Import the platform handler (mainly used by the neural trees)
6364
void ImportBasics(PlatformSupport* p, Alignment* a){Plat = p; A_man=a;}
6465

66+
//Set web mode (structured stdout output with delimiters)
67+
void SetWebMode(bool wm){webMode = wm;}
68+
6569
//Handle pre-aligned profiles
6670
MultiAlignRec* PreAlignedInput(PlatformSupport* p);
6771

@@ -73,6 +77,13 @@ class MultipleAlignment{
7377
//Print the alignment
7478
void PrintMultipleAlignmentConsensus(MultiAlignRec* alignment=NULL);
7579

80+
//Print enhanced alignment with strand, offset, and full PFM data (webmode stdout)
81+
void PrintEnhancedAlignment(MultiAlignRec* alignment=NULL);
82+
//Print FBP profile to stdout in delimited section (webmode stdout)
83+
void PrintFBPToStdout(Motif* fbp);
84+
//Write enhanced alignment to file (default mode)
85+
void WriteEnhancedAlignment(char* outPrefix, MultiAlignRec* alignment=NULL);
86+
7687
//Align a profile to an existing alignment and return the new alignment
7788
MultiAlignRec* SingleProfileAddition(MultiAlignRec* alignment, Motif* two, int twoID);
7889
//Remove a profile from an existing alignment and return the new alignment

0 commit comments

Comments
 (0)