90aa101ee4f9e47a77b2eac496eca213a787d513 jcasper Mon Jul 22 01:53:32 2019 -0700 Adding table browser support for hic tracks, refs #22316 diff --git src/hg/hgTracks/hicTrack.c src/hg/hgTracks/hicTrack.c index 64e4246..2b8db88 100644 --- src/hg/hgTracks/hicTrack.c +++ src/hg/hgTracks/hicTrack.c @@ -53,173 +53,87 @@ struct hicMeta *metaResult = NULL; if (filename == NULL) { warn("Missing bigDataUrl setting for track %s", tg->track); return NULL; } char *errMsg = hicLoadHeader(filename, &metaResult); if (errMsg != NULL) { tg->networkErrMsg = errMsg; return NULL; } return metaResult; } - -int fetchResolution(struct track *tg) -/* Retrieve the binsize to draw the track in. If the track UI has the resolution - * set as "auto", find the widest resolution that still splits the window into 5000 - * pieces (if possible, otherwise select the smallest resolution). */ -{ -if (tg->customPt == NULL) - tg->customPt = grabHeader(tg); -if (tg->customPt == 0) - return -1; - -struct hicMeta *meta = (struct hicMeta*) tg->customPt; -char *binSizeString = hicUiFetchResolution(cart, tg->track, meta); -if (binSizeString == NULL) - { - warn("Empty binSize string"); - return 0; - } -int result; -if (sameString(binSizeString, "Auto")) - { - int idealRes = (winEnd-winStart)/5000; - char *autoRes = meta->resolutions[meta->nRes-1]; - int i; - for (i=meta->nRes-1; i>= 0; i--) - { - if (atoi(meta->resolutions[i]) < idealRes) - { - autoRes = meta->resolutions[i]; - break; - } - } - result = atoi(autoRes); - } -else - result = atoi(binSizeString); -return result; -} - -char *fetchNormalization(struct track *tg) -/* Fetch the normalization to use for this track. */ -{ -if (tg->customPt == NULL) - tg->customPt = grabHeader(tg); -if (tg->customPt == NULL) - return NULL; -struct hicMeta *meta = (struct hicMeta*) tg->customPt; -return hicUiFetchNormalization(cart, tg->track, meta); -} - - static void loadAndFilterItems(struct track *tg) /* Load all Hi-C items in the current region and identify the window height * and median value for this region. */ { -int *x, *y, numRecords; -double *counts; -int binSize = fetchResolution(tg); -if (binSize == 0) +if (tg->customPt == NULL) + tg->customPt = grabHeader(tg); +if (tg->customPt == NULL) return; -struct hicMeta *meta = (struct hicMeta*)tg->customPt; -char *normalization = fetchNormalization(tg); +struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; + +int binSize = hicUiFetchResolutionAsInt(cart, tg->track, hicFileInfo, winEnd-winStart); +char *normalization = hicUiFetchNormalization(cart, tg->track, hicFileInfo); // Later, we should validate that this file is for the current assembly (see the hicMeta structure) // Note: This is giving it a 0-based, full-closed window. Straw seems to use 1-based coordinates // by default, but accepts 0 as the start of a window without complaint. -struct dyString *windowPos = dyStringNew(0); // Pad the start because we want to display partial interactions if the end of an interacting block is // in view but not the start. Straw won't report interactions if the start of the block isn't in the // supplied position range. int strawStart = winStart - binSize + 1; if (strawStart < 0) strawStart = 0; -char *hicChromName = chromName; -if (meta->ucscToAlias != NULL) - { - hicChromName = (char*) hashFindVal(meta->ucscToAlias, chromName); - if (hicChromName == NULL) - { - hicChromName = chromName; - } - } -dyStringPrintf(windowPos, "%s:%d:%d", hicChromName, strawStart, winEnd-1); - -char *filename = trackDbSettingOrDefault(tg->tdb, "bigDataUrl", NULL); -if (filename == NULL) - return; - -tg->networkErrMsg = Cstraw(normalization, filename, binSize, dyStringContents(windowPos), dyStringContents(windowPos), "BP", &x, &y, &counts, &numRecords); +struct interact *hicItems = NULL; +tg->networkErrMsg = hicLoadData(hicFileInfo, binSize, normalization, chromName, strawStart, winEnd-1, chromName, + strawStart, winEnd-1, &hicItems); // Using the interact structure because it has convenient fields, but this is not interact data and // shouldn't be passed to those functions. -struct interact *hicItems = NULL; -int i = 0, filtNumRecords = 0; +int numRecords = slCount(hicItems), filtNumRecords = 0; tg->maxRange = 0.0; // the max height of an interaction in this window double *countsCopy = NULL; AllocArray(countsCopy, numRecords); -for (i=0; i<numRecords; i++) + +struct interact *thisHic = hicItems; +while (thisHic != NULL) { char *drawMode = hicUiFetchDrawMode(cart, tg->track); - if (isnan(counts[i])) - { - // Yes, apparently NAN is possible with normalized values in some methods. Ignore those. - continue; - } if (sameString(drawMode, HIC_DRAW_MODE_ARC)) { // we omit self-interactions in arc mode (they'd just be weird vertical lines) - if (x[i] == y[i]) + if (sameString(thisHic->sourceChrom, thisHic->targetChrom) && + (thisHic->sourceStart == thisHic->targetStart)) continue; } - countsCopy[filtNumRecords++] = counts[i]; - struct interact *new = NULL; - AllocVar(new); - new->chrom = cloneString(chromName); - // x is always <= y, so x is always the start - new->chromStart = x[i]; - new->chromEnd = y[i]+binSize; - new->name = NULL; - new->score = 0; // ignored - new->value = counts[i]; - new->exp = NULL; - new->color = 0; - new->sourceChrom = cloneString(chromName); - new->sourceStart = x[i]; - new->sourceEnd = x[i]+binSize; - new->targetChrom = cloneString(chromName); - new->targetStart = y[i]; - new->targetEnd = y[i]+binSize; - new->targetName = new->targetStrand = NULL; + countsCopy[filtNumRecords++] = thisHic->value; // Calculate the track draw height required to see this item - int leftx = new->chromStart > winStart ? new->chromStart : winStart; - int rightx = new->chromEnd < winEnd ? new->chromEnd : winEnd; + int leftx = thisHic->chromStart > winStart ? thisHic->chromStart : winStart; + int rightx = thisHic->chromEnd < winEnd ? thisHic->chromEnd : winEnd; double thisHeight = scaleForWindow(insideWidth, winStart, winEnd)*(rightx - leftx)/2.0; // triangle or arc if (sameString(drawMode,HIC_DRAW_MODE_SQUARE)) thisHeight = scaleForWindow(insideWidth, winStart, winEnd)*(winEnd-winStart); // square - always draw the full square if (thisHeight > tg->maxRange) tg->maxRange = thisHeight; - - slAddHead(&hicItems, new); + thisHic = thisHic->next; } // Heuristic for auto-scaling the color gradient based on the scores in view - draw the max color value // at or above 2*median score. tg->graphUpperLimit = 2.0*doubleMedian(filtNumRecords, countsCopy); free(countsCopy); tg->items = hicItems; } void hicLoadItems(struct track *tg) /* Load Hi-C items in (mostly) interact format */ { char *filename = trackDbSettingOrDefault(tg->tdb, "bigDataUrl", NULL); if (filename == NULL) return; @@ -291,33 +205,32 @@ *rightStart = 0; if (*rightEnd > winEnd-winStart) *rightEnd = winEnd-winStart; } static void drawHicTriangle(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw a list of Hi-C interactions in a triangle */ { double xScale = scaleForWindow(width, seqStart, seqEnd); double yScale = xScale; int maxHeight = tg->height; struct interact *hicItem = NULL; -int binSize = fetchResolution(tg); -if (binSize == 0) - return; +struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; +int binSize = hicUiFetchResolutionAsInt(cart, tg->track, hicFileInfo, winEnd-winStart); if (vis == tvDense) { yScale *= 0.5; } double maxScore = getHicMaxScore(tg); Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1); if (colorIxs == NULL) return; // something went wrong with colors for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next) { int leftStart, leftEnd, rightStart, rightEnd; calcItemLeftRightBoundaries(&leftStart, &leftEnd, &rightStart, &rightEnd, binSize, hicItem); @@ -353,31 +266,32 @@ gfxPolyFree(&diamond); } } static void drawHicSquare(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw a Hi-C heatmap as a square */ { double xScale = scaleForWindow(width, seqStart, seqEnd); double yScale = xScale; int maxHeight = tg->height; struct interact *hicItem = NULL; -int binSize = fetchResolution(tg); +struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; +int binSize = hicUiFetchResolutionAsInt(cart, tg->track, hicFileInfo, winEnd-winStart); if (binSize == 0) return; if (vis == tvDense) { yScale *= 0.5; } double maxScore = getHicMaxScore(tg); Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1); if (colorIxs == NULL) return; // something went wrong with colors for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next) { @@ -414,31 +328,32 @@ return 1; if (item1->value < item2->value) return -1; return 0; } static void drawHicArc(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw Hi-C interactions in arc mode */ { double xScale = scaleForWindow(width, seqStart, seqEnd); double yScale = xScale; int maxHeight = tg->height; struct interact *hicItem = NULL; -int binSize = fetchResolution(tg); +struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; +int binSize = hicUiFetchResolutionAsInt(cart, tg->track, hicFileInfo, winEnd-winStart); if (binSize == 0) return; if (vis == tvDense) { yScale *= 0.5; } double maxScore = getHicMaxScore(tg); Color *colorIxs = colorSetForHic(hvg, tg, HIC_SCORE_BINS+1); if (colorIxs == NULL) return; // something went wrong with colors slSort(&tg->items, cmpHicItems); // So that the darkest arcs are drawn on top and not lost for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next)