40a345b04f483a7e67494e62afc8528675eb587e braney Mon Mar 6 12:06:43 2023 -0800 make sure alignment blockse are single coverage over the query. diff --git src/hg/hgTracks/snake.c src/hg/hgTracks/snake.c index 61e8425..215f29e 100644 --- src/hg/hgTracks/snake.c +++ src/hg/hgTracks/snake.c @@ -16,30 +16,40 @@ #include "chainCart.h" #include "errCatch.h" #include "twoBit.h" #include "bigWarn.h" #include #include "trackHub.h" #include "limits.h" #include "snakeUi.h" #include "bits.h" #include "trix.h" #include "chromAlias.h" #include "bigPsl.h" #include "snake.h" +static int snakeFeatureCmpScore(const void *va, const void *vb) +/* sort by score of the alignment. */ +{ +const struct snakeFeature *a = *((struct snakeFeature **)va); +const struct snakeFeature *b = *((struct snakeFeature **)vb); +int diff = b->score - a->score; + +return diff; +} + static int snakeFeatureCmpQStart(const void *va, const void *vb) /* sort by start position on the query sequence */ { const struct snakeFeature *a = *((struct snakeFeature **)va); const struct snakeFeature *b = *((struct snakeFeature **)vb); int diff = a->qStart - b->qStart; if (diff == 0) { diff = a->start - b->start; } return diff; } @@ -1135,76 +1145,112 @@ firstLf = lf; for (;lf; lf = next) { next = lf->next; if (!sameString(firstLf->name, lf->name) && (lf->components != NULL)) { slSort(&firstLf->components, snakeFeatureCmpQStart); firstLf->next = lf; firstLf = lf; } for (sf = (struct snakeFeature *)lf->components; sf != NULL; sf = nextSf) { sf->qName = lf->name; sf->orientation = lf->orientation; + sf->score = lf->score; nextSf = sf->next; if (firstLf != lf) { lf->components = NULL; slAddHead(&firstLf->components, sf); } } } if (firstLf != NULL) { slSort(&firstLf->components, snakeFeatureCmpQStart); firstLf->next = 0; } } void snakeDrawLeftLabels() { } static void makeSnakeFeatures(struct linkedFeatures *lf) +/* allocate an info structure for every block in the alignment. */ { for(; lf; lf = lf->next) { struct simpleFeature *sf = lf->components; struct snakeFeature *sfList = NULL; for(;sf; sf = sf->next) { struct snakeFeature *this; AllocVar(this); *(struct simpleFeature *)this = *sf; this->orientation = lf->orientation; slAddHead(&sfList, this); } lf->components = (struct simpleFeature *)sfList; } } +static void makeSingleCoverage(struct linkedFeatures *lf) +/* Because snakes are a display of O+O of the query sequence projected onto the reference sequence, + * we need to only have one copy of each piece of the query sequence. */ +{ +for(; lf; lf = lf->next) // for each query sequence + { + slSort(&lf->components, snakeFeatureCmpScore); // we want to choose the higher scoring alignements + Bits *qBits = bitAlloc(lf->qSize); // the bit array we use to keep track if we've seen this query sequence + struct simpleFeature *sf = lf->components; + struct simpleFeature *prevSf = NULL; + + for(; sf ; sf = sf->next) + { + // have we seen this query range? + if (bitCountRange(qBits, sf->qStart, sf->qEnd - sf->qStart)) + { + // if we've seen this query sequence, then delete it + if (prevSf == NULL) + lf->components = sf->next; + else + prevSf->next = sf->next; + } + else + { + bitSetRange(qBits, sf->qStart, sf->qEnd - sf->qStart); + prevSf = sf; + } + } + + slSort(&lf->components, snakeFeatureCmpQStart); + } +} + void maybeLoadSnake(struct track *track) /* check to see if we're doing snakes and if so load the correct methods. */ { boolean doSnake = cartOrTdbBoolean(cart, track->tdb, "doSnake", FALSE); if (doSnake) { track->drawLeftLabels = snakeDrawLeftLabels; track->itemHeight = snakeItemHeight; track->totalHeight = snakeHeight; track->drawItemAt = snakeDrawAt; track->drawItems = snakeDraw; slSort(&track->items, linkedFeaturesCmpName); makeSnakeFeatures(track->items); fixItems(track->items); + makeSingleCoverage(track->items); track->visibility = track->limitedVis = tvFull; track->canPack = FALSE; } }