34f380bfb0b4003a23fe2e00be6bdac6af326cda jcasper Mon Dec 15 15:20:13 2025 -0800 Adding hicArcLimit and hicArcLimitEnabled settings to let people prevent excessive arc counts from overwhelming a Hi-C display with data, refs #36774 diff --git src/hg/hgTracks/hicTrack.c src/hg/hgTracks/hicTrack.c index ec4053ddb49..789abd0cc38 100644 --- src/hg/hgTracks/hicTrack.c +++ src/hg/hgTracks/hicTrack.c @@ -145,58 +145,62 @@ { // a bit of pointer play to avoid repeated calls to slRemoveEl *prevNextPtr = thisHic->next; // set prev element's next to the following element slAddHead(&filteredOut, thisHic); thisHic = *prevNextPtr; // restore thisHic to point to the next element continue; } } if (sameString(drawMode, HIC_DRAW_MODE_ARC)) { // we omit self-interactions in arc mode (they'd just be weird vertical lines) if (sameString(thisHic->sourceChrom, thisHic->targetChrom) && (thisHic->sourceStart == thisHic->targetStart)) { - thisHic = thisHic->next; + // a bit of pointer play to avoid repeated calls to slRemoveEl + *prevNextPtr = thisHic->next; // set prev element's next to the following element + slAddHead(&filteredOut, thisHic); + thisHic = *prevNextPtr; // restore thisHic to point to the next element continue; } } countsCopy[filtNumRecords++] = thisHic->value; // Calculate the track draw height required to see this item int leftx = max(thisHic->chromStart, winStart); int rightx = min(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; prevNextPtr = &thisHic->next; thisHic = thisHic->next; } if (filteredOut != NULL) interactFreeList(&filteredOut); // Heuristic for auto-scaling the color gradient based on the scores in view - draw the max color value // at or above 2*median score. if (filtNumRecords > 0) tg->graphUpperLimit = 2.0*doubleMedian(filtNumRecords, countsCopy); else tg->graphUpperLimit = 0.0; + if (countsCopy != NULL) freeMem(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; if (tg->customPt == NULL) { tg->customPt = grabHeader(tg); struct track *hicInNextWindow = tg->nextWindow; @@ -425,54 +429,68 @@ struct interact *hicItem = NULL; struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; int binSize = hicUiFetchResolutionAsInt(cart, tg->tdb, hicFileInfo, winEnd-winStart); boolean invert = hicUiFetchInverted(cart, tg->tdb); if (binSize == 0) return; yScale *= hicSqueezeFactor(vis); 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) +hicItem = (struct interact *)tg->items; +if (hicUiArcLimitEnabled(cart,tg->tdb) && (hicUiGetArcLimit(cart, tg->tdb) > 0)) + { + // limit to only the X highest scoring interactions + int itemCount = slCount(tg->items); + int limit = hicUiGetArcLimit(cart, tg->tdb); + while (itemCount > limit && hicItem != NULL) + { + hicItem = hicItem->next; + itemCount--; + } + } + +for (; hicItem; hicItem = hicItem->next) { int leftStart = hicItem->sourceStart - winStart; int leftMidpoint = leftStart + binSize/2; int rightStart = hicItem->targetStart - winStart; int rightMidpoint = rightStart + binSize/2; + if ((leftMidpoint < 0) || (leftMidpoint > winEnd-winStart)) continue; // skip this item - we'd be drawing to a point off the screen if ((rightMidpoint < 0) || (rightMidpoint > winEnd-winStart)) continue; // skip this item - we'd be drawing to a point off the screen int colorIx; if (hicItem->value > maxScore) colorIx = colorIxs[HIC_SCORE_BINS]; else colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)]; double leftx = xScale * leftMidpoint; double rightx = xScale * rightMidpoint; double midx = xScale * (rightMidpoint+leftMidpoint)/2.0; double midy = yScale * (rightMidpoint-leftMidpoint)/2.0; + midy *= 1.5; // Heuristic scaling for better use of vertical space if (!invert) midy = maxHeight-(int)midy; - midy *= 1.5; // Heuristic scaling for better use of vertical space int lefty = maxHeight, righty = maxHeight; // the height of the endpoints if (invert) lefty = righty = 0; hvGfxCurve(hvg, (int)leftx+xOff, lefty+yOff, (int)midx+xOff, midy+yOff, (int)rightx+xOff, righty+yOff, colorIx, FALSE); } } void hicDrawItems(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 set of Hi-C interactions with the current user settings. */ { char *drawMode = hicUiFetchDrawMode(cart, tg->tdb); if (sameString(drawMode,HIC_DRAW_MODE_SQUARE))