6dcfa9d5af42d4b7968f39d8c1b4a53c62a481f9 braney Fri Sep 6 16:03:04 2013 -0700 added pack and squish modes to snake display, big clean up. #10637 diff --git src/hg/hgTracks/snakeTrack.c src/hg/hgTracks/snakeTrack.c index 29009da..d40f41d 100644 --- src/hg/hgTracks/snakeTrack.c +++ src/hg/hgTracks/snakeTrack.c @@ -1,102 +1,106 @@ +#ifdef USE_HAL /* snakeTrack - stuff to load and display snake type tracks in browser. */ -/* uses standard chains from the database or HAL files */ -/* probably the chain and hal support should be in different files - * but they share drawing code - */ #include "common.h" #include "hash.h" #include "localmem.h" #include "linefile.h" #include "jksql.h" #include "hdb.h" #include "hgTracks.h" #include "chainBlock.h" #include "chainLink.h" #include "chainDb.h" #include "chainCart.h" #include "errCatch.h" #include "twoBit.h" #include "bigWarn.h" #include <pthread.h> #include "trackHub.h" #include "values.h" #include "snakeUi.h" -#ifdef USE_HAL - -#ifdef USE_HAL #include "halBlockViz.h" -#endif struct snakeFeature { struct snakeFeature *next; int start, end; /* Start/end in browser coordinates. */ int qStart, qEnd; /* query start/end */ - int level; /* level in packed snake */ + int level; /* level in snake */ int orientation; /* strand... -1 is '-', 1 is '+' */ boolean drawn; /* did we draw this feature? */ char *sequence; /* may have sequence, or NULL */ char *qName; /* chrom name on other species */ }; -// static machinery to calculate packed snake - -struct level +static int snakeFeatureCmpTStart(const void *va, const void *vb) +/* sort by start position on the target sequence */ { -boolean init; /* has this level been initialized */ -int orientation; /* strand.. see above */ -unsigned long edge; /* the leading edge of this level */ -int adjustLevel; /* used to compress out the unused levels */ -boolean hasBlock; /* are there any blocks in this level */ -}; - -static struct level Levels[1000000]; /* for packing the snake, not re-entrant! */ -static int maxLevel = 0; /* deepest level */ +const struct snakeFeature *a = *((struct snakeFeature **)va); +const struct snakeFeature *b = *((struct snakeFeature **)vb); +int diff = a->start - b->start; -/* blocks that make it through the min size filter */ -static struct snakeFeature *newList = NULL; +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; } + +// static machinery to calculate full and pack snake + +struct level +{ +boolean init; /* has this level been initialized */ +int orientation; /* strand.. see above */ +unsigned long edge; /* the leading edge of this level */ +int adjustLevel; /* used to compress out the unused levels */ +boolean hasBlock; /* are there any blocks in this level */ +}; + +static struct level Levels[10000]; /* for packing the snake, not re-entrant! */ +static int maxLevel = 0; /* deepest level */ + +/* blocks that make it through the min size filter */ +static struct snakeFeature *newList = NULL; + static void clearLevels() -/* clear out the data structure that we use to pack the snake */ +/* clear out the data structure that we use to calculate full snakes */ { int ii; for(ii=0; ii < sizeof(Levels) / sizeof(Levels[0]); ii++) Levels[ii].init = FALSE; maxLevel = 0; } -static void calcSnake(struct snakeFeature *list, int level) -// calculate the packed snake +static void calcFullSnakeHelper(struct snakeFeature *list, int level) +// calculate a full snake // updates global newList with unsorted blocks that pass the min // size filter. { struct snakeFeature *cb = list; struct snakeFeature *proposedList = NULL; if (level > maxLevel) maxLevel = level; if (level > ArraySize(Levels)) errAbort("too many levels"); if (Levels[level].init == FALSE) { // initialize the level if this is the first time we've seen it Levels[level].init = TRUE; @@ -121,53 +125,53 @@ if ((Levels[level].orientation != cb->orientation) || ((cb->orientation == 1) && (Levels[level].edge > cb->start)) || ((cb->orientation == -1) && (Levels[level].edge < cb->end))) { // add this to the list of an insert slAddHead(&insertHead, cb); continue; } // the current block will fit on this level // go ahead and deal with the blocks that wouldn't if (insertHead) { // we had an insert, go ahead and calculate where that goes slReverse(&insertHead); - calcSnake(insertHead, level + 1); + calcFullSnakeHelper(insertHead, level + 1); insertHead = NULL; } // assign the current block to this level cb->level = level; if (cb->orientation == 1) Levels[level].edge = cb->end; else Levels[level].edge = cb->start; // add this block to the list of proposed blocks for this level slAddHead(&proposedList, cb); } // we're at the end of the list. Deal with any blocks // that didn't fit on this level if (insertHead) { slReverse(&insertHead); int nextLevel = level + 1; - calcSnake(insertHead, nextLevel); + calcFullSnakeHelper(insertHead, nextLevel); insertHead = NULL; } // do we have any proposed blocks if (proposedList == NULL) return; // we parsed all the blocks in the list to see if they fit in our level // now let's see if the list of blocks for this level is big enough // to actually add struct snakeFeature *temp; double scale = scaleForWindow(insideWidth, winStart, winEnd); int start, end; @@ -187,139 +191,50 @@ errAbort("size of a list of blocks should not be less than zero"); // check to see if the apparent size is big enough if (apparentSize < 1) return; // transfer proposedList to new block list for(temp=proposedList; temp; temp = next) { next = temp->next; temp->next = NULL; slAddHead(&newList, temp); } } -struct cartOptions - { - enum chainColorEnum chainColor; /* ChromColors, ScoreColors, NoColors */ - int scoreFilter ; /* filter chains by score if > 0 */ - }; - -static int snakeHeight(struct track *tg, enum trackVisibility vis) -/* calculate height of all the snakes being displayed */ -{ -if (vis == tvDense) - return tg->lineHeight; - -int height = 0; -struct slList *item = tg->items; - -item = tg->items; - -for (item=tg->items;item; item = item->next) - { - height += tg->itemHeight(tg, item); - } -return height; -} - -// mySQL code to read in chains - -static void doQuery(struct sqlConnection *conn, char *fullName, - struct lm *lm, struct hash *hash, - int start, int end, boolean isSplit, int chainId) -/* doQuery- check the database for chain elements between - * start and end. Use the passed hash to resolve chain - * id's and place the elements into the right - * linkedFeatures structure - */ -{ -struct sqlResult *sr = NULL; -char **row; -struct linkedFeatures *lf; -struct snakeFeature *sf; -struct dyString *query = newDyString(1024); -char *force = ""; - -if (isSplit) - force = "force index (bin)"; - -if (chainId == -1) - sqlDyStringPrintf(query, - "select chainId,tStart,tEnd,qStart from %sLink %-s where ", - fullName, force); -else - sqlDyStringPrintf(query, - "select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ", - fullName, chainId); -if (!isSplit) - sqlDyStringPrintf(query, "tName='%s' and ", chromName); -hAddBinToQuery(start, end, query); -dyStringPrintf(query, "tStart<%u and tEnd>%u", end, start); -sr = sqlGetResult(conn, query->string); - -/* Loop through making up simple features and adding them - * to the corresponding linkedFeature. */ -while ((row = sqlNextRow(sr)) != NULL) - { - lf = hashFindVal(hash, row[0]); - if (lf != NULL) - { - struct chain *pChain = lf->extra; - lmAllocVar(lm, sf); - sf->start = sqlUnsigned(row[1]); - sf->end = sqlUnsigned(row[2]); - sf->qStart = sqlUnsigned(row[3]); - - sf->qEnd = sf->qStart + (sf->end - sf->start); - if ((pChain) && pChain->qStrand == '-') - { - int temp; - - temp = sf->qStart; - sf->qStart = pChain->qSize - sf->qEnd; - sf->qEnd = pChain->qSize - temp; - } - sf->orientation = lf->orientation; - slAddHead(&lf->components, sf); - } - } -sqlFreeResult(&sr); -dyStringFree(&query); -} - struct snakeInfo { int maxLevel; } snakeInfo; -static void calcPackSnake(struct track *tg, void *item) +static void calcFullSnake(struct track *tg, void *item) { struct linkedFeatures *lf = (struct linkedFeatures *)item; if (lf->components == NULL) return; // we use the codons field to keep track of whether we already // calculated the height of this snake if (lf->codons == NULL) { clearLevels(); struct snakeFeature *sf; // this will destroy lf->components, and add to newList - calcSnake((struct snakeFeature *)lf->components, 0); + calcFullSnakeHelper((struct snakeFeature *)lf->components, 0); lf->components = (struct simpleFeature *)newList; newList = NULL; slSort(&lf->components, snakeFeatureCmpQStart); // now we're going to compress the levels that aren't used // to do that, we need to see which blocks are on the screen, // or connected to something on the screen int oldMax = maxLevel; clearLevels(); struct snakeFeature *prev = NULL; for(sf=(struct snakeFeature *)lf->components; sf; prev = sf, sf = sf->next) { if (Levels[sf->level].init == FALSE) { Levels[sf->level].init = TRUE; @@ -362,118 +277,275 @@ count++; } maxLevel = count - 1; // remap blocks for(sf=(struct snakeFeature *)lf->components; sf; sf = sf->next) sf->level = Levels[sf->level].adjustLevel; struct snakeInfo *si; AllocVar(si); si->maxLevel = maxLevel; lf->codons = (struct simpleFeature *)si; } } -static int packSnakeItemHeight(struct track *tg, void *item) +static void calcPackSnakeHelper(struct snakeFeature *list, int level) +// calculate a packed snake +// updates global newList with unsorted blocks that pass the min +// size filter. +{ +struct snakeFeature *cb = list; +struct snakeFeature *proposedList = NULL; + +if (level > maxLevel) + maxLevel = level; +if (level > ArraySize(Levels)) + errAbort("too many levels"); + +if (Levels[level].init == FALSE) + { + // initialize the level if this is the first time we've seen it + Levels[level].init = TRUE; + Levels[level].edge = 0; + } + +// now we step through the blocks and assign them to levels +struct snakeFeature *next; +struct snakeFeature *insertHead = NULL; +for(; cb; cb = next) + { + // we're going to add this block to a different list + // so keep track of the next pointer + next = cb->next; + + // if this block can't fit on this level add to the insert + // list and move on to the next block + if ( Levels[level].edge > cb->start) + { + // add this to the list of an insert + slAddHead(&insertHead, cb); + continue; + } + + // the current block will fit on this level + // go ahead and deal with the blocks that wouldn't + if (insertHead) + { + // we had an insert, go ahead and calculate where that goes + slReverse(&insertHead); + calcPackSnakeHelper(insertHead, level + 1); + insertHead = NULL; + } + + // assign the current block to this level + cb->level = level; + + Levels[level].edge = cb->end; + + // add this block to the list of proposed blocks for this level + slAddHead(&proposedList, cb); + } + +// we're at the end of the list. Deal with any blocks +// that didn't fit on this level +if (insertHead) + { + slReverse(&insertHead); + calcPackSnakeHelper(insertHead, level + 1); + insertHead = NULL; + } + +// do we have any proposed blocks +if (proposedList == NULL) + return; + +// we parsed all the blocks in the list to see if they fit in our level +// now let's see if the list of blocks for this level is big enough +// to actually add + +struct snakeFeature *temp; +double scale = scaleForWindow(insideWidth, winStart, winEnd); +int start, end; + +// order the blocks so lowest start position is first +slReverse(&proposedList); + +start=proposedList->start; +for(temp=proposedList; temp->next; temp = temp->next) + ; +end=temp->end; + +// calculate how big the string of blocks is in screen coordinates +double apparentSize = scale * (end - start); + +if (apparentSize < 0) + errAbort("size of a list of blocks should not be less than zero"); + +// check to see if the apparent size is big enough +if (apparentSize < 1) + return; + +// transfer proposedList to new block list +for(temp=proposedList; temp; temp = next) + { + next = temp->next; + temp->next = NULL; + slAddHead(&newList, temp); + } +} + +static void calcPackSnake(struct track *tg, void *item) +{ +struct linkedFeatures *lf = (struct linkedFeatures *)item; +if (lf->components == NULL) + return; + +// we use the codons field to keep track of whether we already +// calculated the height of this snake +if (lf->codons == NULL) + { + clearLevels(); + + // this will destroy lf->components, and add to newList + calcPackSnakeHelper((struct snakeFeature *)lf->components, 0); + lf->components = (struct simpleFeature *)newList; + newList = NULL; + + //slSort(&lf->components, snakeFeatureCmpQStart); + + struct snakeInfo *si; + AllocVar(si); + si->maxLevel = maxLevel; + lf->codons = (struct simpleFeature *)si; + } +} + +static int snakeItemHeight(struct track *tg, void *item) // return height of a single packed snake { -if (item == NULL) +if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense)) return 0; + struct linkedFeatures *lf = (struct linkedFeatures *)item; if (lf->components == NULL) return 0; + +if (tg->visibility == tvFull) + calcFullSnake(tg, item); +else if (tg->visibility == tvPack) calcPackSnake(tg, item); + struct snakeInfo *si = (struct snakeInfo *)lf->codons; int lineHeight = tg->lineHeight ; return (si->maxLevel + 1) * (2 * lineHeight); } -static int snakeItemHeight(struct track *tg, void *item) -{ -return packSnakeItemHeight(tg, item); -} - static int linkedFeaturesCmpScore(const void *va, const void *vb) /* Help sort linkedFeatures by score */ { const struct linkedFeatures *a = *((struct linkedFeatures **)va); const struct linkedFeatures *b = *((struct linkedFeatures **)vb); if (a->score > b->score) return -1; else if (a->score < b->score) return 1; return 0; } +static int snakeHeight(struct track *tg, enum trackVisibility vis) +/* calculate height of all the snakes being displayed */ +{ +if (vis == tvDense) + return tg->lineHeight; + +if (vis == tvSquish) + return tg->lineHeight/2; + +int height = 0; +struct slList *item = tg->items; + +item = tg->items; + +for (item=tg->items;item; item = item->next) + { + height += tg->itemHeight(tg, item); + } +return height; +} + static void snakeDraw(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw linked features items. */ { struct slList *item; int y; struct linkedFeatures *lf; double scale = scaleForWindow(width, seqStart, seqEnd); int height = snakeHeight(tg, vis); hvGfxSetClip(hvg, xOff, yOff, width, height); +if ((tg->visibility == tvFull) || (tg->visibility == tvPack)) + { // score snakes by how many bases they cover for (item = tg->items; item != NULL; item = item->next) { lf = (struct linkedFeatures *)item; struct snakeFeature *sf; lf->score = 0; for (sf = (struct snakeFeature *)lf->components; sf != NULL; sf = sf->next) { lf->score += sf->end - sf->start; } } slSort(&tg->items, linkedFeaturesCmpScore); + } y = yOff; for (item = tg->items; item != NULL; item = item->next) { if(tg->itemColor != NULL) color = tg->itemColor(tg, item, hvg); tg->drawItemAt(tg, item, hvg, xOff, y, scale, font, color, vis); if (vis == tvFull) y += tg->itemHeight(tg, item); } } -static void packSnakeDrawAt(struct track *tg, void *item, +static void snakeDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a single simple bed item at position. */ { unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH); struct linkedFeatures *lf = (struct linkedFeatures *)item; + + +if (tg->visibility == tvFull) + calcFullSnake(tg, item); +else if (tg->visibility == tvPack) calcPackSnake(tg, item); if (lf->components == NULL) return; -#ifdef USE_HAL boolean isHalSnake = lf->isHalSnake; -#else -boolean isHalSnake = FALSE; -#endif struct snakeFeature *sf = (struct snakeFeature *)lf->components, *prevSf = NULL; int s = tg->itemStart(tg, item); int sClp = (s < winStart) ? winStart : s; int x1 = round((sClp - winStart)*scale) + xOff; int textX = x1; int yOff = y; boolean withLabels = (withLeftLabels && (vis == tvFull) && !tg->drawName); unsigned labelColor = MG_BLACK; // draw the labels if (withLabels) { char *name = tg->itemName(tg, item); int nameWidth = mgFontStringWidth(font, name); @@ -508,50 +580,48 @@ hvGfxUnclip(hvgSide); hvGfxSetClip(hvgSide, insideX, yOff, insideWidth, tg->height); } else { if(drawNameInverted) { hvGfxBox(hvg, textX - 1, y, nameWidth+1, tg->heightPer-1, color); hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, MG_WHITE, font, name); } else hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, labelColor, font, name); } } -#ifdef USE_HAL // let's draw some blue bars for the duplications struct hal_target_dupe_list_t* dupeList = lf->dupeList; for(; dupeList ; dupeList = dupeList->next) { struct hal_target_range_t *range = dupeList->tRange; for(; range; range = range->next) { int s = range->tStart; int e = range->tStart + range->size; int sClp = (s < winStart) ? winStart : s; int eClp = (e > winEnd) ? winEnd : e; int x1 = round((sClp - winStart)*scale) + xOff; int x2 = round((eClp - winStart)*scale) + xOff; hvGfxLine(hvg, x1, y , x2, y , MG_BLUE); } } y+=2; -#endif // now we're going to draw the boxes s = sf->start; int lastE = -1; int lastS = -1; int offY = y; int lineHeight = tg->lineHeight ; int tStart, tEnd, qStart; int qs, qe; int heightPer = tg->heightPer; int lastX = -1,lastY = y; int lastQEnd = 0; int lastLevel = -1; int e; @@ -597,40 +667,40 @@ color = darkBlueColor; int w = ex - sx; if (w == 0) w = 1; assert(w > 0); char buffer[1024]; safef(buffer, sizeof buffer, "%d %d",sf->qStart,sf->qEnd); if (sx < insideX) { int olap = insideX - sx; sx = insideX; w -= olap; } char qAddress[4096]; - if (vis == tvFull) + if ((vis == tvFull) || (vis == tvPack) ) { - safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",tg->itemName(tg, item), qs, qe, winEnd - winStart); + safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",sf->qName, qs, qe, winEnd - winStart); mapBoxHgcOrHgGene(hvg, s, e, sx+1, y, w-2, heightPer, tg->track, buffer, buffer, NULL, TRUE, qAddress); } hvGfxBox(hvg, sx, y, w, heightPer, color); // now draw the mismatches if we're at high enough resolution - if ((winBaseCount < showSnpWidth) && (vis == tvFull)) + if ((winBaseCount < showSnpWidth) && ((vis == tvFull) || (vis == tvPack))) { char *twoBitString = trackDbSetting(tg->tdb, "twoBit"); static struct twoBitFile *tbf = NULL; static char *lastTwoBitString = NULL; static struct dnaSeq *seq = NULL; static char *lastQName = NULL; // sequence for chain snakes is in 2bit files which we cache if (!isHalSnake) { if (twoBitString == NULL) twoBitString = "/gbdb/hg19/hg19.2bit"; if ((lastTwoBitString == NULL) || differentString(lastTwoBitString, twoBitString)) @@ -689,31 +759,31 @@ int myw = myex - mysx; spreadAlignString(hvg, mysx, y, myw, heightPer, MG_WHITE, font, ourDna, extraSeq->dna, seqLen, TRUE, FALSE); } } sf->drawn = TRUE; tEnd = e; tStart = s; qStart = sf->qStart; lastY = y; lastLevel = sf->level; //lastX = x; } -if (vis == tvDense) +if (vis != tvFull) return; // now we're going to draw the lines between the blocks lastX = -1,lastY = y; lastQEnd = 0; lastLevel = 0; qe = lastQEnd = 0; prevSf = NULL; for (sf = (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next) { int y1, y2; int sx, ex; qs = sf->qStart; qe = sf->qEnd; @@ -791,76 +861,307 @@ hvGfxLine(hvg, lastX, y1, sx, y2, color); mapBoxHgcOrHgGene(hvg, s, e, lastX, y1, sx-lastX, 1, tg->track, "", buffer, NULL, TRUE, NULL); } } } else if (lastLevel > sf->level) { hvGfxLine(hvg, lastX, y1, sx, y2, color); hvGfxLine(hvg, sx, y2, sx, y2 - lineHeight - lineHeight/3, color); char buffer[1024]; safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd); mapBoxHgcOrHgGene(hvg, s, e, sx, y2 - lineHeight - lineHeight/3, 2, lineHeight + lineHeight/3, tg->track, "", buffer, NULL, TRUE, NULL); - } - else + } + else + { + char buffer[1024]; + safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd); + if (sf->orientation == -1) + { + hvGfxLine(hvg, lastX-1, y1, ex, y2, color); + hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color); + mapBoxHgcOrHgGene(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track, + "", buffer, NULL, TRUE, NULL); + } + else + { + hvGfxLine(hvg, lastX-1, y1, sx, y2, color); + hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color); + mapBoxHgcOrHgGene(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track, + "", buffer, NULL, TRUE, NULL); + + } + } + } + } + tEnd = e; + tStart = s; + qStart = sf->qStart; + if (sf->orientation == -1) + lastX = sx; + else + lastX = ex; + lastS = s; + lastE = e; + lastLevel = sf->level; + lastQEnd = qe; + } +} + +void halSnakeLoadItems(struct track *tg) +// load up a snake from a HAL file. This code is called in threads +// so *no* use of globals please. All but full snakes are read into a single +// linked feature. +{ +unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, + SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH); + +// if we have a network error we want to put out a message about it +struct errCatch *errCatch = errCatchNew(); +if (errCatchStart(errCatch)) + { + char *fileName = trackDbSetting(tg->tdb, "bigDataUrl"); + char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies"); + int handle = halOpenLOD(fileName); + int needSeq = (winBaseCount < showSnpWidth) ? 1 : 0; + struct hal_block_results_t *head = halGetBlocksInTargetRange(handle, otherSpecies, trackHubSkipHubName(database), chromName, winStart, winEnd, needSeq, 1); + + // did we get any blocks from HAL + if (head == NULL) + { + errCatchEnd(errCatch); + return; + } + struct hal_block_t* cur = head->mappedBlocks; + struct linkedFeatures *lf; + struct hash *qChromHash = newHash(5); + struct linkedFeatures *lfList = NULL; + char buffer[4096]; + +#ifdef NOTNOW + struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; + + for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) + { + printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom); + struct hal_target_range_t *range = targetDupeBlocks->tRange; + for(; range; range = range->next) + { + printf("<br> %ld : %ld\n", range->tStart, range->size); + } + } +#endif + + while (cur) + { + struct hashEl* hel; + + //safef(buffer, sizeof buffer, "%s.%c", cur->qChrom,cur->strand); + if (tg->visibility == tvFull) + safef(buffer, sizeof buffer, "%s", cur->qChrom); + else + { + // make sure the block is on the screen + if (!positiveRangeIntersection(winStart, winEnd, cur->tStart, cur->tStart + cur->size)) + { + cur = cur->next; + continue; + } + safef(buffer, sizeof buffer, "allInOne"); + } + + if ((hel = hashLookup(qChromHash, buffer)) == NULL) + { + AllocVar(lf); + lf->isHalSnake = TRUE; + slAddHead(&lfList, lf); + lf->start = 0; + lf->end = 1000000000; + lf->grayIx = maxShade; + lf->name = cloneString(buffer); + lf->extra = cloneString(buffer); + lf->orientation = (cur->strand == '+') ? 1 : -1; + hashAdd(qChromHash, lf->name, lf); + + // now figure out where the blue bars go + struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; + + if ((tg->visibility == tvPack) || (tg->visibility == tvFull)) + for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) + { + if ((tg->visibility == tvPack) || + ((tg->visibility == tvFull) && + (sameString(targetDupeBlocks->qChrom, cur->qChrom)))) + { + struct hal_target_dupe_list_t* dupeList; + AllocVar(dupeList); + *dupeList = *targetDupeBlocks; + slAddHead(&lf->dupeList, dupeList); + // TODO: should clone the target_range structures + // rather than copying them + } + } + } + else + { + lf = hel->val; + } + + struct snakeFeature *sf; + AllocVar(sf); + slAddHead(&lf->components, sf); + + sf->start = cur->tStart; + sf->end = cur->tStart + cur->size; + sf->qStart = cur->qStart; + sf->qEnd = cur->qStart + cur->size; + sf->orientation = (cur->strand == '+') ? 1 : -1; + sf->sequence = cloneString(cur->sequence); + sf->qName = cur->qChrom; + + cur = cur->next; + } + if (tg->visibility == tvFull) + { + for(lf=lfList; lf ; lf = lf->next) + { + slSort(&lf->components, snakeFeatureCmpQStart); + } + } + else if (tg->visibility == tvPack) + { + assert(lf->next == NULL); + slSort(&lf->components, snakeFeatureCmpTStart); + } + + //halFreeBlocks(head); + //halClose(handle, myThread); + + tg->items = lfList; + } +errCatchEnd(errCatch); +if (errCatch->gotError) + { + tg->networkErrMsg = cloneString(errCatch->message->string); + tg->drawItems = bigDrawWarning; + tg->totalHeight = bigWarnTotalHeight; + } +errCatchFree(&errCatch); +} + +void halSnakeDrawLeftLabels(struct track *tg, int seqStart, int seqEnd, + struct hvGfx *hvg, int xOff, int yOff, int width, int height, + boolean withCenterLabels, MgFont *font, + Color color, enum trackVisibility vis) +{ +} + +void halSnakeMethods(struct track *tg, struct trackDb *tdb, + int wordCount, char *words[]) +{ +linkedFeaturesMethods(tg); +tg->canPack = tdb->canPack = TRUE; +tg->loadItems = halSnakeLoadItems; +tg->drawItems = snakeDraw; +tg->mapItemName = lfMapNameFromExtra; +tg->subType = lfSubChain; +//tg->extraUiData = (void *) chainCart; +tg->totalHeight = snakeHeight; +tg->drawLeftLabels = halSnakeDrawLeftLabels; + +tg->drawItemAt = snakeDrawAt; +tg->itemHeight = snakeItemHeight; +} +#endif // USE_HAL + +#ifdef NOTNOW + +// from here down are routines to support the visualization of chains as snakes +// this code is currently BROKEN, and may be removed completely in the future + +struct cartOptions + { + enum chainColorEnum chainColor; /* ChromColors, ScoreColors, NoColors */ + int scoreFilter ; /* filter chains by score if > 0 */ + }; + +// mySQL code to read in chains + +static void doQuery(struct sqlConnection *conn, char *fullName, + struct lm *lm, struct hash *hash, + int start, int end, boolean isSplit, int chainId) +/* doQuery- check the database for chain elements between + * start and end. Use the passed hash to resolve chain + * id's and place the elements into the right + * linkedFeatures structure + */ +{ +struct sqlResult *sr = NULL; +char **row; +struct linkedFeatures *lf; +struct snakeFeature *sf; +struct dyString *query = newDyString(1024); +char *force = ""; + +if (isSplit) + force = "force index (bin)"; + +if (chainId == -1) + sqlDyStringPrintf(query, + "select chainId,tStart,tEnd,qStart from %sLink %-s where ", + fullName, force); +else + sqlDyStringPrintf(query, + "select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ", + fullName, chainId); +if (!isSplit) + sqlDyStringPrintf(query, "tName='%s' and ", chromName); +hAddBinToQuery(start, end, query); +dyStringPrintf(query, "tStart<%u and tEnd>%u", end, start); +sr = sqlGetResult(conn, query->string); + +/* Loop through making up simple features and adding them + * to the corresponding linkedFeature. */ +while ((row = sqlNextRow(sr)) != NULL) { - char buffer[1024]; - safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd); - if (sf->orientation == -1) + lf = hashFindVal(hash, row[0]); + if (lf != NULL) { - hvGfxLine(hvg, lastX-1, y1, ex, y2, color); - hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color); - mapBoxHgcOrHgGene(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track, - "", buffer, NULL, TRUE, NULL); - } - else + struct chain *pChain = lf->extra; + lmAllocVar(lm, sf); + sf->start = sqlUnsigned(row[1]); + sf->end = sqlUnsigned(row[2]); + sf->qStart = sqlUnsigned(row[3]); + + sf->qEnd = sf->qStart + (sf->end - sf->start); + if ((pChain) && pChain->qStrand == '-') { - hvGfxLine(hvg, lastX-1, y1, sx, y2, color); - hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color); - mapBoxHgcOrHgGene(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track, - "", buffer, NULL, TRUE, NULL); + int temp; + temp = sf->qStart; + sf->qStart = pChain->qSize - sf->qEnd; + sf->qEnd = pChain->qSize - temp; } + sf->orientation = lf->orientation; + slAddHead(&lf->components, sf); } } - } - tEnd = e; - tStart = s; - qStart = sf->qStart; - if (sf->orientation == -1) - lastX = sx; - else - lastX = ex; - lastS = s; - lastE = e; - lastLevel = sf->level; - lastQEnd = qe; - } -} - - -static void snakeDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, double scale, - MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single simple bed item at position. */ -{ -if ((tg->visibility == tvFull) || (tg->visibility == tvDense)) - packSnakeDrawAt(tg, item, hvg, xOff, y, scale, - font, color, vis); +sqlFreeResult(&sr); +dyStringFree(&query); } static void fixItems(struct linkedFeatures *lf) // put all chain blocks from a single query chromosome into one // linkedFeatures structure { struct linkedFeatures *firstLf, *next; struct snakeFeature *sf, *nextSf; firstLf = lf; for (;lf; lf = next) { next = lf->next; if (!sameString(firstLf->name, lf->name) && (lf->components != NULL)) { @@ -944,144 +1245,30 @@ * one or two lines to the edge of the screen. */ #define STARTSLOP 0 #define MULTIPLIER 10 #define MAXLOOK 100000 extra = (STARTSLOP < maxOverLeft) ? STARTSLOP : maxOverLeft; start = seqStart - extra; extra = (STARTSLOP < maxOverRight) ? STARTSLOP : maxOverRight; end = seqEnd + extra; doQuery(conn, fullName, lm, hash, start, end, isSplit, -1); } } hFreeConn(&conn); } -#ifdef USE_HAL -void halSnakeLoadItems(struct track *tg) -{ -unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, - SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH); -struct errCatch *errCatch = errCatchNew(); -if (errCatchStart(errCatch)) - { - char *fileName = trackDbSetting(tg->tdb, "bigDataUrl"); - char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies"); - int handle = halOpenLOD(fileName); - int needSeq = (winBaseCount < showSnpWidth) ? 1 : 0; - struct hal_block_results_t *head = halGetBlocksInTargetRange(handle, otherSpecies, trackHubSkipHubName(database), chromName, winStart, winEnd, needSeq, 1); - - // did we get any blocks from HAL - if (head == NULL) - { - errCatchEnd(errCatch); - return; - } - struct hal_block_t* cur = head->mappedBlocks; - struct linkedFeatures *lf; - struct hash *qChromHash = newHash(5); - struct linkedFeatures *lfList = NULL; - char buffer[4096]; - -#ifdef NOTNOW - struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; - - for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) - { - printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom); - struct hal_target_range_t *range = targetDupeBlocks->tRange; - for(; range; range = range->next) - { - printf("<br> %ld : %ld\n", range->tStart, range->size); - } - } -#endif - - while (cur) - { - struct hashEl* hel; - - //safef(buffer, sizeof buffer, "%s.%c", cur->qChrom,cur->strand); - safef(buffer, sizeof buffer, "%s", cur->qChrom); - if ((hel = hashLookup(qChromHash, buffer)) == NULL) - { - AllocVar(lf); - lf->isHalSnake = TRUE; - slAddHead(&lfList, lf); - lf->start = 0; - lf->end = 1000000000; - lf->grayIx = maxShade; - lf->name = cloneString(buffer); - lf->extra = cloneString(buffer); - lf->orientation = (cur->strand == '+') ? 1 : -1; - hashAdd(qChromHash, lf->name, lf); - - // now figure out where the blue bars go - struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks; - - for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next) - { - if (sameString(targetDupeBlocks->qChrom, cur->qChrom)) - { - struct hal_target_dupe_list_t* dupeList; - AllocVar(dupeList); - *dupeList = *targetDupeBlocks; - slAddHead(&lf->dupeList, dupeList); - // TODO: should clone the target_range structures - } - } - } - else - { - lf = hel->val; - } - - struct snakeFeature *sf; - AllocVar(sf); - slAddHead(&lf->components, sf); - - sf->start = cur->tStart; - sf->end = cur->tStart + cur->size; - sf->qStart = cur->qStart; - sf->qEnd = cur->qStart + cur->size; - sf->orientation = (cur->strand == '+') ? 1 : -1; - sf->sequence = cloneString(cur->sequence); - - // printBlock(stdout, cur); - cur = cur->next; - } - for(lf=lfList; lf ; lf = lf->next) - { - slSort(&lf->components, snakeFeatureCmpQStart); - } - //halFreeBlocks(head); - //halClose(handle, myThread); - - tg->items = lfList; - } -errCatchEnd(errCatch); -if (errCatch->gotError) - { - tg->networkErrMsg = cloneString(errCatch->message->string); - tg->drawItems = bigDrawWarning; - tg->totalHeight = bigWarnTotalHeight; - } -errCatchFree(&errCatch); -} -#endif // USE_HAL - - void snakeLoadItems(struct track *tg) // Load chains from a mySQL database { char *track = tg->table; struct chain chain; int rowOffset; char **row; struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr = NULL; struct linkedFeatures *list = NULL, *lf; int qs; char optionChr[128]; /* Option - chromosome filter */ char *optionChrStr; char extraWhere[128] ; struct cartOptions *chainCart; @@ -1172,87 +1359,30 @@ else slReverse(&list); tg->items = list; /* Clean up. */ sqlFreeResult(&sr); hFreeConn(&conn); /* now load the items */ loadLinks(tg, ourStart, ourEnd, tg->visibility); lf=tg->items; fixItems(lf); } /* chainLoadItems() */ -#ifdef NOTNOW -static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg) -{ -struct linkedFeatures *lf = (struct linkedFeatures *)item; - -return(tg->colorShades[lf->grayIx]); -} - -static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg) -{ -return(tg->ixColor); -} - -static void setNoColor(struct track *tg) -{ -tg->itemColor = chainNoColor; -tg->color.r = 0; -tg->color.g = 0; -tg->color.b = 0; -tg->altColor.r = 127; -tg->altColor.g = 127; -tg->altColor.b = 127; -tg->ixColor = MG_BLACK; -tg->ixAltColor = MG_GRAY; -} -#endif - -#ifdef USE_HAL -void halSnakeDrawLeftLabels(struct track *tg, int seqStart, int seqEnd, - struct hvGfx *hvg, int xOff, int yOff, int width, int height, - boolean withCenterLabels, MgFont *font, - Color color, enum trackVisibility vis) -{ -} - - -void halSnakeMethods(struct track *tg, struct trackDb *tdb, - int wordCount, char *words[]) -{ -//errAbort("halSnakeMethds\n"); -linkedFeaturesMethods(tg); -tg->canPack = FALSE; -tdb->canPack = FALSE; -tg->loadItems = halSnakeLoadItems; -tg->drawItems = snakeDraw; -tg->mapItemName = lfMapNameFromExtra; -tg->subType = lfSubChain; -//tg->extraUiData = (void *) chainCart; -tg->totalHeight = snakeHeight; -tg->drawLeftLabels = halSnakeDrawLeftLabels; - -tg->drawItemAt = snakeDrawAt; -tg->itemHeight = snakeItemHeight; -} -#endif - -#ifdef NOTNOW void snakeMethods(struct track *tg, struct trackDb *tdb, int wordCount, char *words[]) /* Fill in custom parts of alignment chains. */ { struct cartOptions *chainCart; AllocVar(chainCart); boolean normScoreAvailable = chainDbNormScoreAvailable(tdb); /* what does the cart say about coloring option */ chainCart->chainColor = chainFetchColorOption(cart, tdb, FALSE); chainCart->scoreFilter = cartUsualIntClosestToHome(cart, tdb, @@ -1294,17 +1424,41 @@ else chainCart->chainColor = chainColorChromColors; } tg->canPack = FALSE; tg->loadItems = snakeLoadItems; tg->drawItems = snakeDraw; tg->mapItemName = lfMapNameFromExtra; tg->subType = lfSubChain; tg->extraUiData = (void *) chainCart; tg->totalHeight = snakeHeight; tg->drawItemAt = snakeDrawAt; tg->itemHeight = snakeItemHeight; } -#endif + +static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg) +{ +struct linkedFeatures *lf = (struct linkedFeatures *)item; + +return(tg->colorShades[lf->grayIx]); +} + +static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg) +{ +return(tg->ixColor); +} + +static void setNoColor(struct track *tg) +{ +tg->itemColor = chainNoColor; +tg->color.r = 0; +tg->color.g = 0; +tg->color.b = 0; +tg->altColor.r = 127; +tg->altColor.g = 127; +tg->altColor.b = 127; +tg->ixColor = MG_BLACK; +tg->ixAltColor = MG_GRAY; +} #endif