33990deeb6214328424d9acf9bfaf667ae8f3f4f angie Wed Mar 28 15:34:14 2012 -0700 Feature #6152 (Variant Annotation Tool): Added annoStreamWig and annoGrateWig,which led to some significant changes: annoRow is now polymorphic (words[] vs. wig float[]), annoFilter has a new function to apply filter(s) to a single number, and annoFormatTab can print out per-base wiggle values or average wiggle values (hardcoded to do per-base until a real config option is added). One puny test case was verified against mysql & table browser output. diff --git src/hg/lib/annoGrateWig.c src/hg/lib/annoGrateWig.c new file mode 100644 index 0000000..f7766d7 --- /dev/null +++ src/hg/lib/annoGrateWig.c @@ -0,0 +1,78 @@ +/* annoGrateWig -- subclass of annoGrator for wiggle data */ + +#include "annoGrateWig.h" +#include "annoStreamWig.h" +#include "sqlNum.h" +#include "wiggle.h" + +static void tidyUp(struct annoRow *rowIn, struct annoRow **pOutList, + uint primaryStart, uint primaryEnd) +/* This takes a wiggle chunk coming from a .wig/database row and makes it into + * zero or more tidy little NAN-less annoRows. Trim rowIn to the bounds of + * primary, trim NANs from beginning and break into multiple rows where there + * are NANs in the middle. If the rowIn is contiguous with the row at the + * head of outList, expand that row to include rowIn's data. */ +{ +uint start = max(rowIn->start, primaryStart); +uint end = min(rowIn->end, primaryEnd); +float *vector = rowIn->data; +while (end > start) + { + uint offset = start - rowIn->start; + if (vector[offset] == NAN) + start++; + else + { + // If there is a NAN before end, that's the end of this row: + uint thisEnd = start; + while (thisEnd < end && vector[thisEnd - rowIn->start] != NAN) + thisEnd++; + struct annoRow *headRow = *pOutList; + if (headRow == NULL || rowIn->start > headRow->end) + { + // allocate a new row + struct annoRow *rowOut = annoRowWigNew(rowIn->chrom, start, thisEnd, FALSE, + vector + offset); + slAddHead(pOutList, rowOut); + } + else + { + // glom new data onto headRow + assert(thisEnd > headRow->end); + uint oldEnd = headRow->end; + uint oldLen = oldEnd - headRow->start; + uint newLen = thisEnd - headRow->start; + headRow->data = needMoreMem(headRow->data, oldLen, newLen); + headRow->end = thisEnd; + float *newData = (float *)rowIn->data + (oldEnd - rowIn->start); + float *newSpace = (float *)headRow->data + (oldEnd - headRow->start); + CopyArray(newData, newSpace, (thisEnd - oldEnd)); + } + start = thisEnd; + } + } +} + +static struct annoRow *agwdIntegrate(struct annoGrator *self, struct annoRow *primaryRow, + boolean *retRJFilterFailed) +/* Return wig annoRows that overlap primaryRow position, with NANs weeded out. */ +{ +struct annoRow *rowsIn = annoGratorIntegrate(self, primaryRow, retRJFilterFailed); +if (retRJFilterFailed && *retRJFilterFailed) + return NULL; +struct annoRow *rowIn, *rowOutList = NULL;; +for (rowIn = rowsIn; rowIn != NULL; rowIn = rowIn->next) + tidyUp(rowIn, &rowOutList, primaryRow->start, primaryRow->end); +slReverse(&rowOutList); +annoRowFreeList(&rowsIn, -1); +return rowOutList; +} + +struct annoGrator *annoGrateWigDbNew(char *db, char *table, int maxOutput) +/* Create an annoGrator subclass for wiggle data from db.table (and the file it points to). */ +{ +struct annoStreamer *wigSource = annoStreamWigDbNew(db, table, maxOutput); +struct annoGrator *self = annoGratorNew(wigSource); +self->integrate = agwdIntegrate; +return self; +}