34c07fa95c834c1377e4e185b1a9e19499a0d536
kate
Tue Jan 30 15:48:56 2018 -0800
Update schema, based on input from Braney. Improve map boxes. refs #17512
diff --git src/hg/hgTracks/interactTrack.c src/hg/hgTracks/interactTrack.c
index 9650397..222a187 100644
--- src/hg/hgTracks/interactTrack.c
+++ src/hg/hgTracks/interactTrack.c
@@ -1,342 +1,373 @@
/* interactTrack -- draw interaction between two genomic regions */
/* Copyright (C) 2018 The Regents of the University of California
* See README in this or parent directory for licensing information. */
#include "common.h"
#include "hgTracks.h"
#include "interact.h"
#include "interactUi.h"
static int interactTotalHeight(struct track *tg, enum trackVisibility vis)
/* calculate height of all the interactions being displayed */
{
if ( tg->visibility == tvDense)
return tl.fontHeight;
int min, max, deflt, current;
cartTdbFetchMinMaxPixels(cart, tg->tdb,
INTERACT_MINHEIGHT, INTERACT_MAXHEIGHT, atoi(INTERACT_DEFHEIGHT),
&min, &max, &deflt, ¤t);
//uglyf("IN totalHeight=%d. ", current);
// FIXME DEBUG
//return 300;
return tg->height = current;
}
static Color interactItemColor(struct track *tg, void *item, struct hvGfx *hvg)
/* Return color to draw an interaction */
{
struct interact *inter = item;
struct rgbColor itemRgb;
// There must be a better way...
itemRgb.r = (inter->color & 0xff0000) >> 16;
itemRgb.g = (inter->color & 0xff00) >> 8;
itemRgb.b = inter->color & 0xff;
//uglyf("IN color=%X", hvGfxFindColorIx(hvg, itemRgb.r, itemRgb.g, itemRgb.b));
return hvGfxFindColorIx(hvg, itemRgb.r, itemRgb.g, itemRgb.b);
}
void interactLoadItems(struct track *tg)
/* Load all interact items in region */
{
loadSimpleBedWithLoader(tg, (bedItemLoader)interactLoad);
}
+char *getOtherChrom(struct interact *inter)
+/* Get other chromosome from an interaaction. Return NULL if same chromosome */
+{
+if (sameString(inter->sourceChrom, inter->targetChrom))
+ return NULL;
+if (inter->chromStart == inter->sourceStart)
+ return cloneString(inter->targetChrom);
+return cloneString(inter->sourceChrom);
+}
+
static void interactDrawItems(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 interact structures. */
{
#define DRAW_LINE 0
#define DRAW_CURVE 1
#define DRAW_ELLIPSE 2
char *drawMode = cartUsualStringClosestToHome(cart, tg->tdb, FALSE,
INTERACT_DRAW, INTERACT_DRAW_DEFAULT);
int draw = DRAW_LINE;
if (sameString(drawMode, INTERACT_DRAW_CURVE))
draw = DRAW_CURVE;
else if (sameString(drawMode, INTERACT_DRAW_ELLIPSE))
draw = DRAW_ELLIPSE;
double scale = scaleForWindow(width, seqStart, seqEnd);
struct interact *inters = tg->items;
//uglyf("Found %d items. ", slCount(inters));
unsigned int maxWidth = 0;
struct interact *inter;
char buffer[1024];
char itemBuf[2048];
safef(buffer, sizeof buffer, "%s.%s", tg->tdb->track, INTERACT_MINSCORE);
//double minScore = sqlDouble(cartUsualString(cart, buffer, INTERACT_DEFMINSCORE));
// Determine if there are mixed inter and intra-chromosomal
// Suppress interchromosomal labels if they overlap
int nSame = 0, nOther = 0;
int prevLabelEnd = 0, prevLabelStart = 0;
char *prevLabel = 0;
boolean doOtherLabels = TRUE;
+char *otherChrom = NULL;
for (inter=inters; inter; inter=inter->next)
{
int width = inter->chromEnd - inter->chromStart;
if (width > maxWidth)
maxWidth = width;
}
//uglyf("Max width is %d. ", maxWidth);
for (inter=inters; inter; inter=inter->next)
{
- if (sameString(inter->chrom1, inter->chrom2))
+ otherChrom = getOtherChrom(inter);
+ if (otherChrom == NULL)
nSame++;
else
{
nOther++;
if (!doOtherLabels)
continue;
- int labelWidth = vgGetFontStringWidth(hvg->vg, font, inter->chrom2);
+ int labelWidth = vgGetFontStringWidth(hvg->vg, font, otherChrom);
// TODO: simplify now that center approach is abandoned
int sx = ((inter->chromStart - seqStart) + .5) * scale + xOff; // x coord of center
int labelStart = (double)sx - labelWidth/2;
int labelEnd = labelStart + labelWidth - 1;
- char *otherChrom = (inter->strand[0] == '+') ? inter->chrom2 : inter->chrom1;
if (labelStart <= prevLabelEnd &&
!(labelStart == prevLabelStart && labelEnd == prevLabelEnd &&
sameString(otherChrom, prevLabel)))
doOtherLabels = FALSE;
prevLabelStart = labelStart;
prevLabelEnd = labelEnd;
- prevLabel = inter->chrom2;
+ prevLabel = otherChrom;
}
}
int fontHeight = vgGetFontPixelHeight(hvg->vg, font);
int otherHeight = (nOther) ? 3 * fontHeight : 0;
int sameHeight = (nSame) ? tg->height - otherHeight: 0;
// Draw items
//uglyf("IN seqStart=%d", seqStart);
for (inter=inters; inter; inter=inter->next)
{
+ char *otherChrom = getOtherChrom(inter);
safef(itemBuf, sizeof itemBuf, "%s", inter->name);
struct dyString *ds = dyStringNew(0);
dyStringPrintf(ds, "%s", inter->name);
if (inter->score)
dyStringPrintf(ds, " %d", inter->score);
char *statusBuf = dyStringCannibalize(&ds);
//uglyf("statusBuf: %s. ", statusBuf);
color = interactItemColor(tg, inter, hvg);
// TODO: simplify by using start/end instead of center and width
// This is a holdover from longRange track implementation
-
- // set lower and upper regions from item1 and item2, which may be ordered by type rather
- // than genomic position (e.g. item1 are snp's, item2 are genes)
unsigned lowStart, lowEnd, highStart, highEnd;
- if (inter->chromStart1 < inter->chromStart2)
+ if (otherChrom)
{
- lowStart = inter->chromStart1;
- lowEnd = inter->chromEnd1;
- highStart = inter->chromStart2;
- highEnd = inter->chromEnd2;
+ lowStart = inter->chromStart;
+ lowEnd = inter->chromEnd;
}
- else
+ else if (inter->sourceStart < inter->targetStart)
{
- lowStart = inter->chromStart2;
- lowEnd = inter->chromEnd2;
- highStart = inter->chromStart1;
- highEnd = inter->chromEnd1;
+ lowStart = inter->sourceStart;
+ lowEnd = inter->sourceEnd;
+ highStart = inter->targetStart;
+ highEnd = inter->targetEnd;
}
- // TODO: cleanup
- if (differentString(inter->chrom1, inter->chrom2))
+ else
{
- lowStart = inter->chromStart;
- lowEnd = inter->chromEnd;
+ lowStart = inter->targetStart;
+ lowEnd = inter->targetEnd;
+ highStart = inter->sourceStart;
+ highEnd = inter->sourceEnd;
}
+
unsigned s = lowStart + ((double)(lowEnd - lowStart + .5) / 2);
int sx = ((s - seqStart) + .5) * scale + xOff; // x coord of center (lower region)
//uglyf("
IN seqStart=%d, start=%d, start1=%d, end1=%d, start2=%d, end2=%d, end=%d, s=%d, sx=%d. ",
//seqStart, inter->chromStart, inter->chromStart1, inter->chromEnd1,
//inter->chromStart2, inter->chromEnd2, inter->chromEnd, s, sx);
unsigned sw = lowEnd - lowStart;
int sFootWidth = scale * (double)sw / 2; // width in pixels of half foot (lower)
if (sFootWidth == 0)
sFootWidth = 1;
unsigned e = highStart + (double)(highEnd - highStart + .5) / 2;
int ex = ((e - seqStart) + .5) * scale + xOff;
unsigned ew = highEnd - highStart;
int eFootWidth = scale * (double)ew / 2;
if (eFootWidth == 0)
eFootWidth = 1;
//uglyf("
IN s=%d, sx=%d, sw=%d, sFootWidth=%d. e=%d, ex=%d, ew=%d, eFootWidth=%d, chromStart=%d",
//s, sx, sw, sFootWidth, e, ex, ew, eFootWidth, inter->chromStart);
//uglyf("
IN start1=%d, end1=%d, start2=%d, end2=%d.",
//inter->chromStart1, inter->chromEnd1, inter->chromStart2, inter->chromEnd2);
- if (differentString(inter->chrom1, inter->chrom2))
+ if (otherChrom)
{
// different chromosomes
// draw below same chrom items, if any
unsigned yPos = 0;
int height = 0;
int yOffOther = yOff;
if (tg->visibility == tvDense)
{
height = tg->height;
}
else
{
height = otherHeight/2;
yOffOther = yOff + sameHeight;
}
yPos = yOffOther + height;
// draw the foot
- int footWidth = sFootWidth;
- hvGfxLine(hvg, sx - footWidth, yOffOther, sx + footWidth, yOffOther, color);
+ hvGfxLine(hvg, sx - sFootWidth, yOffOther, sx + sFootWidth, yOffOther, color);
// draw the vertical
- if (inter->strand[0] == '+')
+ if (sameString(inter->chrom, inter->sourceChrom))
hvGfxLine(hvg, sx, yOffOther, sx, yPos, color);
else
hvGfxDottedLine(hvg, sx, yOffOther, sx, yPos, color);
if (tg->visibility == tvFull)
{
- mapBoxHgcOrHgGene(hvg, s, s, sx - 2, yOffOther, 4, height,
- tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
- safef(buffer, sizeof buffer, "%s", inter->strand[0] == '+' ?
- inter->chrom2 : inter->chrom1);
+ // add map box to foot
+ char *nameBuf = (inter->chromStart == inter->sourceStart ?
+ inter->sourceName : inter->targetName);
+uglyf("foot name: %s. ", nameBuf);
+ mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
+ sx - sFootWidth, yOffOther, sFootWidth * 2, 4,
+ tg->track, itemBuf, nameBuf, NULL, TRUE, NULL);
+ // add map box to vertical
+ mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd, sx - 2, yOffOther, 4, height,
+ tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
if (doOtherLabels)
{
+ safef(buffer, sizeof buffer, "%s", sameString(inter->chrom, inter->sourceChrom) ?
+ inter->targetChrom : inter->sourceChrom);
hvGfxTextCentered(hvg, sx, yPos + 2, 4, 4, MG_BLUE, font, buffer);
int width = vgGetFontStringWidth(hvg->vg, font, buffer);
- mapBoxHgcOrHgGene(hvg, s, s, sx - width/2, yPos,
+
+ // add mapBox to label
+ mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd, sx - width/2, yPos,
width, fontHeight, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
}
}
continue;
}
// draw same chromosome interaction
boolean sOnScreen = (s >= seqStart) && (s < seqEnd);
boolean eOnScreen = (e >= seqStart) && (e < seqEnd);
//uglyf("
IN s=%d, e=%d, sOn: %d, eOn: %d. ", s, e, sOnScreen, eOnScreen);
//if (s>e)
//uglyf("
IN s>e start=%d, start1=%d, end1=%d, start2=%d, end2=%d, end=%d, s=%d, sx=%d. ",
//inter->chromStart, inter->chromStart1, inter->chromEnd1,
//inter->chromStart2, inter->chromEnd2, inter->chromEnd, s, sx);
double interWidth = e - s;
int peakHeight = (sameHeight - 15) * ((double)interWidth / maxWidth) + 10;
int peak = yOff + peakHeight;
if (tg->visibility == tvDense)
peak = yOff + tg->height;
if (sOnScreen)
{
- // draw foot of first region and mapbox
+ // draw foot of lower region
hvGfxLine(hvg, sx - sFootWidth, yOff, sx + sFootWidth, yOff, color);
- mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
- sx - sFootWidth - 2, yOff, sx + sFootWidth + 2, 4,
- tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
// draw vertical
if (!eOnScreen || draw == DRAW_LINE)
{
- if (inter->strand[0] == '-')
+ if (inter->chromStart == inter->targetStart)
hvGfxDottedLine(hvg, sx, yOff, sx, peak, color);
else
hvGfxLine(hvg, sx, yOff, sx, peak, color);
}
}
if (eOnScreen)
{
- // draw foot and mapbox of second region
+ // draw foot of upper region
hvGfxLine(hvg, ex - eFootWidth, yOff, ex + eFootWidth, yOff, color);
- mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
- ex - eFootWidth - 2, yOff, ex + eFootWidth + 2, 4,
- tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
// draw vertical
if (!sOnScreen || draw == DRAW_LINE)
{
- if (inter->strand[0] == '-')
- hvGfxDottedLine(hvg, ex, yOff, ex, peak, color); //OLD
+ if (inter->chromStart == inter->targetStart)
+ hvGfxDottedLine(hvg, ex, yOff, ex, peak, color);
else
- hvGfxLine(hvg, ex, yOff, ex, peak, color); //OLD
+ hvGfxLine(hvg, ex, yOff, ex, peak, color);
}
}
if (tg->visibility == tvFull)
{
+ char *nameBuf = NULL;
+ if (sOnScreen)
+ {
+ /* add mapbox to lower region */
+ nameBuf = (inter->chromStart == inter->sourceStart ?
+ inter->sourceName : inter->targetName);
+ mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
+ sx - sFootWidth, yOff, sFootWidth * 2, 4,
+ tg->track, itemBuf, nameBuf, NULL, TRUE, NULL);
+ }
+ if (eOnScreen)
+ {
+ /* add mapbox to upper region */
+ nameBuf = (inter->chromEnd == inter->targetEnd ?
+ inter->targetName : inter->sourceName);
+ mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
+ ex - eFootWidth, yOff, eFootWidth * 2, 4,
+ tg->track, itemBuf, nameBuf, NULL, TRUE, NULL);
+ }
if (sOnScreen && eOnScreen && draw != DRAW_LINE)
{
- boolean isDotted = (inter->strand[0] == '-');
+ boolean isDotted = (inter->sourceStart > inter->targetStart);
if (draw == DRAW_CURVE)
{
int peakX = ((ex - sx + 1) / 2) + sx;
int peakY = peak + 30;
hvGfxCurve(hvg, sx, yOff, peakX, peakY, ex, yOff, color, isDotted);
// map box on peak
// FIXME: not working
/*mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
peakX - 2, peakY - 2, 4, 4,
tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
*/
}
else if (draw == DRAW_ELLIPSE)
{
int yLeft = yOff + peakHeight;
int yTop = yOff - peakHeight;
hvGfxEllipseDraw(hvg, sx, yLeft, ex, yTop, color, ELLIPSE_BOTTOM, isDotted);
// map box on peak
// FIXME: not working
/*mapBoxHgcOrHgGene(hvg, inter->chromStart, inter->chromEnd,
sx - sFootWidth - 2, yOff + peakHeight, 4, 4,
tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
*/
}
}
else
{
// draw link horizontal line between regions (dense mode just shows feet ??)
unsigned ePeak = eOnScreen ? ex : xOff + width;
unsigned sPeak = sOnScreen ? sx : xOff;
- if (inter->strand[0] == '-')
+ if (inter->sourceStart > inter->targetStart)
hvGfxDottedLine(hvg, sPeak, peak, ePeak, peak, color);
else
hvGfxLine(hvg, sPeak, peak, ePeak, peak, color);
// map box on horizontal line
mapBoxHgcOrHgGene(hvg, s, e, sPeak, peak-2, ePeak - sPeak, 4,
tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
// map boxes on verticals
if (sOnScreen)
mapBoxHgcOrHgGene(hvg, s, e, sx - 2, yOff, 4, peak - yOff,
tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
if (eOnScreen)
mapBoxHgcOrHgGene(hvg, s, e, ex - 2, yOff, 4, peak - yOff,
tg->track, itemBuf, statusBuf, NULL, TRUE, NULL);
}
}
}
}
void interactDrawLeftLabels(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)
/* Override default */
{
}
void interactMethods(struct track *tg)
/* Interact track type methods */
{
//tg->bedSize = 6;
//bedMethods(tg);
tg->loadItems = interactLoadItems;
tg->drawItems = interactDrawItems;
tg->drawLeftLabels = interactDrawLeftLabels;
tg->totalHeight = interactTotalHeight;
tg->mapsSelf = TRUE;
}