e7f02d37914178e82c5f2b481cf6f294c6687d39 jcasper Mon Nov 28 16:35:16 2022 -0800 Allow users to invert Hi-C plots, refs #30330, #30343 diff --git src/hg/hgTracks/hicTrack.c src/hg/hgTracks/hicTrack.c index 322cc02..684482d 100644 --- src/hg/hgTracks/hicTrack.c +++ src/hg/hgTracks/hicTrack.c @@ -276,146 +276,166 @@ *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; struct hicMeta *hicFileInfo = (struct hicMeta*)tg->customPt; int binSize = hicUiFetchResolutionAsInt(cart, tg->tdb, hicFileInfo, winEnd-winStart); +boolean invert = hicUiFetchInverted(cart, tg->tdb); 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 for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next) { int leftStart, leftEnd, rightStart, rightEnd; calcItemLeftRightBoundaries(&leftStart, &leftEnd, &rightStart, &rightEnd, binSize, hicItem); int colorIx; if (hicItem->value > maxScore) colorIx = colorIxs[HIC_SCORE_BINS]; else colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)]; // adding four polygon points for a diamond, based on the starts and ends of the source and target coordinate ranges. struct gfxPoly *diamond = gfxPolyNew(); // left point of the diamond double x = xScale * (leftStart+rightStart)/2.0; double y = yScale * (rightStart-leftStart)/2.0; - gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff); + if (!invert) + y = maxHeight-(int)y; + gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff); // top point of the diamond x = xScale * (leftStart+rightEnd)/2.0; y = yScale * (rightEnd-leftStart)/2.0; - gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff); + if (!invert) + y = maxHeight-(int)y; + gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff); // right point of the diamond x = xScale * ((leftEnd + rightEnd)/2.0); y = yScale * (rightEnd-leftEnd)/2.0; - gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff); + if (!invert) + y = maxHeight-(int)y; + gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff); // bottom point of the diamond x = xScale * (leftEnd+rightStart)/2.0; y = yScale * (rightStart-leftEnd)/2.0; - gfxPolyAddPoint(diamond, (int)x+xOff, maxHeight-(int)y+yOff); + if (!invert) + y = maxHeight-(int)y; + gfxPolyAddPoint(diamond, (int)x+xOff, (int)y+yOff); hvGfxDrawPoly(hvg, diamond, colorIx, TRUE); 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; 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 for (hicItem = (struct interact *)tg->items; hicItem; hicItem = hicItem->next) { int leftStart, leftEnd, rightStart, rightEnd; calcItemLeftRightBoundaries(&leftStart, &leftEnd, &rightStart, &rightEnd, binSize, hicItem); int colorIx; if (hicItem->value > maxScore) colorIx = colorIxs[HIC_SCORE_BINS]; else colorIx = colorIxs[(int)(HIC_SCORE_BINS * hicItem->value/maxScore)]; double x = xScale * leftStart; double y = yScale * ((winEnd-winStart)-rightStart); - hvGfxBox(hvg, (int)x+xOff, maxHeight-(int)y+yOff, (int)(xScale*(leftEnd-leftStart))+1, (int)(yScale*(rightEnd-rightStart))+1, colorIx); + y = maxHeight-(int)y; + if (invert) // when inverted, the top left of the box corresponds to rightEnd instead of rightStart + y = yScale * ((winEnd-winStart)-rightEnd); + hvGfxBox(hvg, (int)x+xOff, (int)y+yOff, (int)(xScale*(leftEnd-leftStart))+1, (int)(yScale*(rightEnd-rightStart))+1, colorIx); if (leftStart != rightStart) { x = xScale * rightStart; y = yScale * ((winEnd-winStart)-leftStart); - hvGfxBox(hvg, (int)x+xOff, maxHeight-(int)y+yOff, (int)(xScale*(rightEnd-rightStart))+1, (int)(yScale*(leftEnd-leftStart))+1, colorIx); + y = maxHeight-(int)y; + if (invert) + y = yScale * ((winEnd-winStart)-leftEnd); + hvGfxBox(hvg, (int)x+xOff, (int)y+yOff, (int)(xScale*(rightEnd-rightStart))+1, (int)(yScale*(leftEnd-leftStart))+1, colorIx); } } // Draw top-left to bottom-right diagonal axis line in black int colorIx = hvGfxFindColorIx(hvg, 0, 0, 0); + if (invert) // Draw bottom-left to top-right instead + hvGfxLine(hvg, xOff, maxHeight+yOff, ((winEnd-winStart)*xScale)+xOff, yOff, colorIx); + else hvGfxLine(hvg, xOff, yOff, ((winEnd-winStart)*xScale)+xOff, maxHeight+yOff, colorIx); } int cmpHicItems(const void *elem1, const void *elem2) /* Comparison function for sorting Hi-C interactions by score */ { struct interact *item1 = *((struct interact**)elem1); struct interact *item2 = *((struct interact**)elem2); if (item1->value > item2->value) 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; 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) { int leftStart = hicItem->sourceStart - winStart; int leftMidpoint = leftStart + binSize/2; @@ -424,33 +444,38 @@ 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; + if (!invert) + midy = maxHeight-(int)midy; midy *= 1.5; // Heuristic scaling for better use of vertical space - hvGfxCurve(hvg, (int)leftx+xOff, maxHeight+yOff, (int)midx+xOff, maxHeight-(int)midy+yOff, - (int)rightx+xOff, maxHeight+yOff, colorIx, FALSE); + 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)) drawHicSquare(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); else if (sameString(drawMode,HIC_DRAW_MODE_TRIANGLE)) drawHicTriangle(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); else if (sameString(drawMode,HIC_DRAW_MODE_ARC)) drawHicArc(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);