src/hg/hgTracks/coverageTrack.c 1.8
1.8 2010/06/05 19:29:42 braney
add support for 32-bit color (make USE_PNG have global consequence)
Index: src/hg/hgTracks/coverageTrack.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/hgTracks/coverageTrack.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -b -B -U 1000000 -r1.7 -r1.8
--- src/hg/hgTracks/coverageTrack.c 3 Sep 2008 19:19:01 -0000 1.7
+++ src/hg/hgTracks/coverageTrack.c 5 Jun 2010 19:29:42 -0000 1.8
@@ -1,714 +1,714 @@
/* Put up clone/coverage track */
#include "common.h"
#include "hash.h"
#include "linefile.h"
#include "jksql.h"
#include "hdb.h"
#include "hgTracks.h"
#include "obscure.h"
#include "spaceSaver.h"
#include "glDbRep.h"
#include "clonePos.h"
struct cloneFrag
/* A fragment of a clone. */
{
struct cloneFrag *next; /* Next in list. */
char *name; /* Name of fragment. Not allocated here. */
};
struct cloneFragPos
/* An alignment involving a clone frag. */
{
struct cloneFragPos *next; /* Next in list. */
struct cloneFrag *frag; /* Fragment info. */
struct psl *psl; /* Alignment info. Memory owned here. Possibly NULL. */
struct gl *gl; /* Golden path position info. */
int start, end; /* Start end in chromosome. */
};
struct cloneInfo
/* Info about a clone and where it aligns. */
{
struct cloneInfo *next; /* Next in list */
char *name; /* Name of clone. (Not allocated here) */
short phase; /* Htg phase - 1 2 or 3. */
char stage; /* Stage - (P)redraft, (D)raft, (F)inished. */
struct cloneFrag *fragList; /* List of fragments. */
int fragCount; /* Count of fragments. */
struct cloneFragPos *cfaList; /* List of alignments. */
struct spaceSaver *ss; /* How this is layed out. */
int cloneStart, cloneEnd; /* Min/Max position of alignments. */
};
int cmpCloneInfo(const void *va, const void *vb)
/* Compare two cloneInfos by cloneStart. */
{
const struct cloneInfo *a = *((struct cloneInfo **)va);
const struct cloneInfo *b = *((struct cloneInfo **)vb);
return a->cloneStart - b->cloneStart;
}
void cloneInfoFree(struct cloneInfo **pCi)
/* free up a clone info. */
{
struct cloneInfo *ci;
if ((ci = *pCi) != NULL)
{
struct cloneFragPos *cfa;
for (cfa = ci->cfaList; cfa != NULL; cfa = cfa->next)
{
pslFree(&cfa->psl);
glFree(&cfa->gl);
}
slFreeList(&ci->cfaList);
slFreeList(&ci->fragList);
freez(pCi);
}
}
void cloneInfoFreeList(struct cloneInfo **pList)
/* Free up a list of cloneInfo's. */
{
struct cloneInfo *el,*next;
for (el = *pList; el != NULL; el = next)
{
next = el->next;
cloneInfoFree(&el);
}
*pList = NULL;
}
struct cloneFrag *findCloneFrag(struct cloneInfo *ci, char *fragName)
/* Search for named frag and return it, or NULL if not found. */
{
struct cloneFrag *frag;
for (frag = ci->fragList; frag != NULL; frag = frag->next)
{
if (sameString(frag->name, fragName))
return frag;
}
return NULL;
}
void layoutCloneAli(struct cloneInfo *ci)
/* Figure out space saver layout for alignments in clone. */
{
struct spaceSaver *ss;
struct cloneFragPos *cfa;
ss = ci->ss = spaceSaverNew(winStart, winEnd, 100);
for (cfa = ci->cfaList; cfa != NULL; cfa = cfa->next)
{
spaceSaverAdd(ss, cfa->start, cfa->end, cfa);
}
spaceSaverFinish(ss);
}
char *cloneName(struct track *tg, void *item)
/* Return name of gold track item. */
{
struct cloneInfo *ci = item;
return ci->name;
}
int cloneFragMaxWin = 1500000;
int oneOrRowCount(struct cloneInfo *ci)
/* Return row count, but at least one. */
{
int rowCount = ci->ss->rowCount;
if (rowCount < 1) rowCount = 1;
return rowCount;
}
static int cloneItemHeight(struct track *tg, void *item)
/* Return item height for fixed height track. */
{
struct cloneInfo *ci = item;
int height1 = tl.fontHeight+1;
if (winBaseCount <= cloneFragMaxWin)
return height1*oneOrRowCount(ci)+2;
else
return height1;
}
static int cloneItemStart(struct track *tg, void *item)
/* Return start of item on clone track. */
{
struct cloneInfo *ci = item;
return ci->cloneStart;
}
static int cloneItemEnd(struct track *tg, void *item)
/* Return end of item on clone track. */
{
struct cloneInfo *ci = item;
return ci->cloneEnd;
}
static int cloneTotalHeight(struct track *tg, enum trackVisibility vis)
/* Height of a clone track. */
{
switch (vis)
{
case tvFull:
{
int total = 0;
struct cloneInfo *ci;
for (ci = tg->items; ci != NULL; ci = ci->next)
{
total += tg->itemHeight(tg, ci);
}
tg->height = total+2;
break;
}
case tvDense:
tg->lineHeight = tl.fontHeight+1;
tg->heightPer = tg->lineHeight - 1;
tg->height = tg->lineHeight;
break;
case tvHide:
case tvPack:
case tvSquish:
break;
}
return tg->height;
}
static void drawOneClone(struct cloneInfo *ci, int seqStart, int seqEnd,
struct hvGfx *hvg, int xOff, int yOff, int width,
MgFont *font, int lineHeight, Color color, boolean stagger,
boolean hiliteDupes, boolean nofrag)
/* Draw a single clone item - using space saver layout on fragments. */
{
struct cloneFragPos *cfa;
struct psl *psl;
int y;
int heightPer = lineHeight-1;
struct spaceSaver *ss = ci->ss;
int baseWidth = seqEnd - seqStart;
struct spaceNode *sn;
int x1, x2, w;
char *s;
int textWidth;
char fullPos[256];
struct hash *dupeHash = NULL;
Color col;
struct hashEl *hel;
if (hiliteDupes)
{
struct hash *uniqHash = newHash(7);
dupeHash = newHash(6);
for (sn = ss->nodeList; sn != NULL; sn = sn->next)
{
cfa = sn->val;
if (cfa->end - cfa->start > 1000)
{
s = strchr(cfa->frag->name, '_');
if (s != NULL)
{
s += 1;
if (hashLookup(uniqHash, s) == NULL)
{
hashAdd(uniqHash, s, NULL);
}
else /* Got a dupe! */
{
if ((hel = hashLookup(dupeHash, s)) == NULL)
hashAdd(dupeHash, s, sn);
}
}
}
}
freeHash(&uniqHash);
}
for (sn = ss->nodeList; sn != NULL; sn = sn->next)
{
if (stagger)
y = yOff + sn->row*lineHeight;
else
y = yOff;
cfa = sn->val;
x1 = roundingScale(cfa->start-winStart, width, baseWidth)+xOff;
x2 = roundingScale(cfa->end-winStart, width, baseWidth)+xOff;
/* Clip here so that text will tend to be more visible... */
if (x1 < xOff)
x1 = xOff;
if (x2 > xOff + width)
x2 = xOff + width;
w = x2-x1;
if (w < 1)
w = 1;
s = strchr(cfa->frag->name, '_');
if (s == NULL)
s = "";
else
s += 1;
col = color;
if (hiliteDupes)
{
if ((hel = hashLookup(dupeHash, s)) != NULL)
{
if (hel->val == sn)
col = MG_RED;
else
col = MG_BLUE;
}
}
hvGfxBox(hvg, x1, y, w, heightPer, col);
textWidth = mgFontStringWidth(font, s);
if ((textWidth <= w) && (!nofrag))
hvGfxTextCentered(hvg, x1, y, w, heightPer, MG_WHITE, font, s);
if (baseWidth <= 2000000)
{
psl = cfa->psl;
if (psl != NULL)
{
sprintf(fullPos, "%s %d to %d of %d, strand %s, hits %d to %d",
psl->qName, psl->qStart,
psl->qEnd, psl->qSize, psl->strand,
psl->tStart, psl->tEnd);
mapBoxHc(hvg, cfa->start, cfa->end, x1,y,w,heightPer, "hgClone", cfa->frag->name, fullPos);
}
else
mapBoxHc(hvg, cfa->start, cfa->end, x1,y,w,heightPer, "hgClone", cfa->frag->name, cfa->frag->name);
}
}
freeHash(&dupeHash);
}
/* These tables are for combining sequence scores.
* 0 = no coverage
* 1 = predraft
* 2 = draft
* 3 = deep draft
* 4 = finished */
static UBYTE predraftInc[5] = {1, 1, 2, 3, 4};
static UBYTE draftInc[5] = {2, 2, 3, 3, 4};
static UBYTE finishedInc[5] = {4, 4, 4, 4, 4};
void incStage(UBYTE *b, int width, char stage)
/* Increment b from 0 to width-1 according to stage. */
{
UBYTE *inc = NULL;
int i;
if (stage == 'P')
inc = predraftInc;
else if (stage == 'D')
inc = draftInc;
else if (stage == 'F')
inc = finishedInc;
else
{
warn("Unknown stage %c (%d)", stage, stage);
inc = draftInc;
}
for (i=0; i<width; ++i)
b[i] = inc[b[i]];
}
void resampleBytes(UBYTE *s, int sct, UBYTE *d, int dct)
/* Shrink or stretch an line of bytes. */
{
#define WHOLESCALE 256
if (sct > dct) /* going to do some averaging */
{
int i;
int j, jend, lj;
long lasts, ldiv;
long acc, div;
long t1,t2;
ldiv = WHOLESCALE;
lasts = s[0];
lj = 0;
for (i=0; i<dct; i++)
{
acc = lasts*ldiv;
div = ldiv;
t1 = (i+1)*(long)sct;
jend = t1/dct;
for (j = lj+1; j<jend; j++)
{
acc += s[j]*WHOLESCALE;
div += WHOLESCALE;
}
t2 = t1 - jend*(long)dct;
lj = jend;
lasts = s[lj];
if (t2 == 0)
{
ldiv = WHOLESCALE;
}
else
{
ldiv = WHOLESCALE*t2/dct;
div += ldiv;
acc += lasts*ldiv;
ldiv = WHOLESCALE-ldiv;
}
*d++ = acc/div;
}
}
else if (dct == sct) /* they's the same */
{
while (--dct >= 0)
*d++ = *s++;
}
else if (sct == 1)
{
while (--dct >= 0)
*d++ = *s;
}
else/* going to do some interpolation */
{
int i;
long t1;
long p1;
long err;
int dct2;
dct -= 1;
sct -= 1;
dct2 = dct/2;
t1 = 0;
for (i=0; i<=dct; i++)
{
p1 = t1/dct;
err = t1 - p1*dct;
if (err == 0)
*d++ = s[p1];
else
*d++ = (s[p1]*(dct-err)+s[p1+1]*err+dct2)/dct;
t1 += sct;
}
}
}
static void cloneDenseDraw(struct track *tg, int seqStart, int seqEnd,
struct hvGfx *hvg, int xOff, int yOff, int width,
MgFont *font, Color color, enum trackVisibility vis)
/* Draw dense clone items. */
{
int baseWidth = seqEnd - seqStart;
UBYTE *useCounts;
UBYTE *aveCounts;
int lineHeight = mgFontLineHeight(font);
struct cloneInfo *ci;
struct cloneFragPos *cfa; /* List of alignments. */
int s, e, w;
int log2 = digitsBaseTwo(baseWidth);
int shiftFactor = log2 - 17;
int sampleWidth;
if (shiftFactor < 0)
shiftFactor = 0;
sampleWidth = (baseWidth>>shiftFactor);
AllocArray(useCounts, sampleWidth);
AllocArray(aveCounts, width);
memset(useCounts, 0, sampleWidth * sizeof(useCounts[0]));
for (ci = tg->items; ci != NULL; ci = ci->next)
{
char stage = ci->stage;
for (cfa = ci->cfaList; cfa != NULL; cfa = cfa->next)
{
s = ((cfa->start - seqStart)>>shiftFactor);
e = ((cfa->end - seqStart)>>shiftFactor);
if (s < 0) s = 0;
if (e > sampleWidth) e = sampleWidth;
w = e - s;
if (w > 0)
incStage(useCounts+s, w, stage);
}
}
resampleBytes(useCounts, sampleWidth, aveCounts, width);
grayThreshold(aveCounts, width);
-hvGfxVerticalSmear(hvg,xOff,yOff,width,lineHeight,aveCounts,TRUE);
+hvGfxVerticalSmear8(hvg,xOff,yOff,width,lineHeight,aveCounts,TRUE);
freeMem(useCounts);
freeMem(aveCounts);
}
static void cloneFullDraw(struct track *tg, int seqStart, int seqEnd,
struct hvGfx *hvg, int xOff, int yOff, int width,
MgFont *font, Color color, enum trackVisibility vis)
/* Draw full clone items. */
{
int y = yOff;
int lineHeight = mgFontLineHeight(font)+1;
struct cloneInfo *ci;
Color light = tg->ixAltColor;
int oneHeight;
int x1, x2, w;
int baseWidth = seqEnd - seqStart;
int tooBig = (winBaseCount > cloneFragMaxWin);
int hilight = MG_CYAN;
int unfinished = MG_GRAY;
Color standard = color;
boolean gotTiling = hTableExists(database, "tilingPath");
struct sqlConnection *conn = NULL;
int bgColor;
char accOnly[64];
boolean nofrag = (strcmp("Clone Coverage/Fragment Position", tg->longLabel));
if (gotTiling)
conn = hAllocConn(database);
for (ci = tg->items; ci != NULL; ci = ci->next)
{
bgColor = light;
if (gotTiling)
{
char query[256], buf[256];
strcpy(accOnly, ci->name);
chopSuffix(accOnly);
sprintf(query, "select accession from tilingPath where accession = '%s'", accOnly);
if (sqlQuickQuery(conn, query, buf, sizeof(buf)) != NULL)
bgColor = hilight;
}
/* Check if track no longer showing fragments (starting with hg15) */
if ((nofrag) && (ci->phase < 3))
color = unfinished;
else
color = standard;
if (!tooBig)
oneHeight = oneOrRowCount(ci)*lineHeight+2;
else
oneHeight = lineHeight;
x1 = roundingScale(ci->cloneStart-winStart, width, baseWidth)+xOff;
x2 = roundingScale(ci->cloneEnd-winStart, width, baseWidth)+xOff;
w = x2-x1;
hvGfxBox(hvg, x1, y, w, oneHeight-1, bgColor);
if (!tooBig)
drawOneClone(ci, seqStart, seqEnd, hvg, xOff, y+1, width, font, lineHeight,
color, TRUE, tg->subType, nofrag);
else
drawOneClone(ci, seqStart, seqEnd, hvg, xOff, y, width, font, oneHeight-1,
color, FALSE, tg->subType, nofrag);
y += oneHeight;
}
hFreeConn(&conn);
}
static void cloneDraw(struct track *tg, int seqStart, int seqEnd,
struct hvGfx *hvg, int xOff, int yOff, int width,
MgFont *font, Color color, enum trackVisibility vis)
/* Draw clone items. */
{
if (vis == tvFull)
cloneFullDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
else
cloneDenseDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis);
}
#ifdef UNUSED
struct hash *realiCloneHash;
struct cloneInfo *realiCloneList;
void loadRealiClonesInWindow()
/* Load up realiCloneHash and realiCloneList with the clones in the window. */
{
if (realiCloneList == NULL)
{
char query[256];
struct sqlConnection *conn = hAllocConn(database);
struct sqlResult *sr = NULL;
char **row;
struct cloneInfo *ci;
struct psl *psl;
char *fragName;
struct cloneFrag *cf;
char cloneName[128];
struct hashEl *hel;
struct cloneFragPos *cfa;
char *s;
struct clonePos cp;
/* Load in clone extents from database. */
realiCloneHash = newHash(12);
sprintf(query,
"select * from cloneAliPos where chrom='%s'and chromStart<%u and chromEnd>%u",
chromName, winEnd, winStart);
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
clonePosStaticLoad(row, &cp);
AllocVar(ci);
hel = hashAdd(realiCloneHash, cp.name, ci);
ci->name = hel->name;
ci->cloneStart = cp.chromStart;
ci->cloneEnd = cp.chromEnd;
ci->phase = cp.phase;
slAddHead(&realiCloneList, ci);
}
sqlFreeResult(&sr);
/* Load in alignments from database and sort them by clone. */
sprintf(query, "select * from %s_frags where tStart<%u and tEnd>%u",
chromName, winEnd, winStart);
sr = sqlGetResult(conn, query);
while ((row = sqlNextRow(sr)) != NULL)
{
psl = pslLoad(row);
fragName = psl->qName;
strcpy(cloneName, fragName);
s = strchr(cloneName, '_');
if (s != NULL)
*s = 0;
if ((hel = hashLookup(realiCloneHash, cloneName)) == NULL)
{
warn("%s not in range in cloneAliPos", cloneName);
continue;
}
ci = hel->val;
if ((cf = findCloneFrag(ci, fragName)) == NULL)
{
AllocVar(cf);
cf->name = fragName;
slAddHead(&ci->fragList, cf);
}
AllocVar(cfa);
cfa->frag = cf;
cfa->psl = psl;
cfa->start = psl->tStart;
cfa->end = psl->tEnd;
slAddHead(&ci->cfaList, cfa);
}
slSort(&realiCloneList, cmpCloneInfo);
sqlFreeResult(&sr);
hFreeConn(&conn);
/* Do preliminary layout processing for each clone. */
for (ci = realiCloneList; ci != NULL; ci = ci->next)
{
slReverse(&ci->cfaList);
layoutCloneAli(ci);
}
}
}
#endif /* UNUSED */
struct hash *glCloneHash;
struct cloneInfo *glCloneList = NULL;
void glLoadInWindow()
/* Load up glCloneHash and glCloneList with the clones in the window. */
{
if (glCloneList == NULL)
{
struct sqlConnection *conn = hAllocConn(database);
struct sqlResult *sr = NULL;
char **row;
struct cloneInfo *ci;
struct gl *gl;
char *fragName;
struct cloneFrag *cf;
char cloneName[128];
struct hashEl *hel;
struct cloneFragPos *cfa;
struct clonePos cp;
char *s;
int rowOffset;
/* Load in clone extents from database. */
glCloneHash = newHash(12);
sr = hRangeQuery(conn, "clonePos", chromName, winStart, winEnd, NULL, &rowOffset);
while ((row = sqlNextRow(sr)) != NULL)
{
clonePosStaticLoad(row+rowOffset, &cp);
AllocVar(ci);
hel = hashAdd(glCloneHash, cp.name, ci);
ci->name = hel->name;
ci->cloneStart = cp.chromStart;
ci->cloneEnd = cp.chromEnd;
ci->phase = cp.phase;
ci->stage = cp.stage[0];
slAddHead(&glCloneList, ci);
}
sqlFreeResult(&sr);
/* Load in gl from database and sort them by clone. */
sr = hRangeQuery(conn, "gl", chromName, winStart, winEnd, NULL, &rowOffset);
while ((row = sqlNextRow(sr)) != NULL)
{
gl = glLoad(row+rowOffset);
fragName = gl->frag;
strcpy(cloneName, fragName);
s = strchr(cloneName, '.');
if (s != NULL)
s = strchr(s, '_');
if (s != NULL)
*s = 0;
if ((hel = hashLookup(glCloneHash, cloneName)) == NULL)
{
if (!sameString(database, "hg4") && !sameString(database, "hg5")
&& !sameString(database, "hg6") && !sameString(database, "hg7"))
/* Honestly, Asif and Jim will fix this someday! */
warn("%s not in range in clonePos", cloneName);
continue;
}
ci = hel->val;
if ((cf = findCloneFrag(ci, fragName)) == NULL)
{
AllocVar(cf);
cf->name = fragName;
slAddHead(&ci->fragList, cf);
}
AllocVar(cfa);
cfa->frag = cf;
cfa->gl = gl;
cfa->start = gl->start;
cfa->end = gl->end;
slAddHead(&ci->cfaList, cfa);
}
slSort(&glCloneList, cmpCloneInfo);
sqlFreeResult(&sr);
hFreeConn(&conn);
/* Do preliminary layout processing for each clone. */
for (ci = glCloneList; ci != NULL; ci = ci->next)
{
slReverse(&ci->cfaList);
layoutCloneAli(ci);
}
}
}
void coverageLoad(struct track *tg)
/* Load up clone alignments from database tables and organize. */
{
glLoadInWindow();
tg->items = glCloneList;
}
void coverageFree(struct track *tg)
/* Free up clone track items. */
{
cloneInfoFreeList(&glCloneList);
freeHash(&glCloneHash);
}
void coverageMethods(struct track *tg)
/* Make track for golden path positions of all frags. */
{
tg->loadItems = coverageLoad;
tg->freeItems = coverageFree;
tg->drawItems = cloneDraw;
tg->itemName = cloneName;
tg->mapItemName = cloneName;
tg->totalHeight = cloneTotalHeight;
tg->itemHeight = cloneItemHeight;
tg->itemStart = cloneItemStart;
tg->itemEnd = cloneItemEnd;
}