f8a3e855ebfc02c2657a0c61b434ced94a373737 angie Wed Apr 20 09:56:55 2011 -0700 Feature #3476 (next block arrows for OMIM tracks): refactored sharedcode from several tracks (Superfamily, GAD, DECIPHER, OMIM*) with similar drawing and mouseover features, made the shared code compatible with nextPrevExon code (which for simple bed tracks like these is more like zap-to-edge), and added simpleBedNextPrevEdge to their *Methods. diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c index 4670e2b..9a25b55 100644 --- src/hg/hgTracks/simpleTracks.c +++ src/hg/hgTracks/simpleTracks.c @@ -122,31 +122,30 @@ #include "variome.h" #endif /* GBROWSE */ #ifdef LOWELAB #include "loweLabTracks.h" #include "rnaPLFoldTrack.h" #endif /* LOWELAB */ #ifdef LOWELAB_WIKI #include "wiki.h" #endif /* LOWELAB_WIKI */ static char const rcsid[] = "$Id: simpleTracks.c,v 1.149 2010/06/05 19:29:42 braney Exp $"; #define CHROM_COLORS 26 #define SMALLDYBUF 64 -#define OMIM_MAX_DESC_LEN 256 int colorBin[MAXPIXELS][256]; /* count of colors for each pixel for each color */ /* Declare our color gradients and the the number of colors in them */ Color shadesOfGreen[EXPR_DATA_SHADES]; Color shadesOfRed[EXPR_DATA_SHADES]; Color shadesOfBlue[EXPR_DATA_SHADES]; Color shadesOfYellow[EXPR_DATA_SHADES]; Color shadesOfGreenOnWhite[EXPR_DATA_SHADES]; Color shadesOfRedOnWhite[EXPR_DATA_SHADES]; Color shadesOfBlueOnWhite[EXPR_DATA_SHADES]; Color shadesOfYellowOnWhite[EXPR_DATA_SHADES]; Color shadesOfRedOnYellow[EXPR_DATA_SHADES]; Color shadesOfBlueOnYellow[EXPR_DATA_SHADES]; Color orangeColor = 0; Color brickColor = 0; @@ -3921,30 +3920,141 @@ void loadEarlyRepBad(struct track *tg) /* Load up bad early replication pairs from table into track items. */ { tg->items = lfsFromBedsInRange("earlyRepBad", winStart, winEnd, chromName); } void earlyRepBadMethods(struct track *tg) /* Fill in track methods for linked features.series */ { linkedFeaturesSeriesMethods(tg); tg->loadItems = loadEarlyRepBad; } #endif /* GBROWSE */ + +// The following few functions are shared by GAD, OMIM, DECIPHER, Superfamily. +// Those tracks need an extra label derived from item name -- the extra label +// is used as mouseover text for each item, and appears to the immediate left +// of the feature in full mode. +struct bedPlusLabel +{ + struct bed bed; // inline, so struct bedPlusLabel * can be cast to struct bed *. + char *label; +}; + +typedef char *labelFromNameFunction(char *name); + +static void bedPlusLabelLoad(struct track *tg, labelFromNameFunction func) +/* Load items from a bed table; if vis is pack or full, add extra label derived from item name. */ +{ +struct bedPlusLabel *itemList = NULL; +struct sqlConnection *conn = hAllocConn(database); +int rowOffset = 0; +struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); +char **row = NULL; +while ((row = sqlNextRow(sr)) != NULL) + { + struct bed *bed = bedLoad(row+rowOffset); + struct bedPlusLabel *item = needMoreMem(bed, sizeof(struct bed), sizeof(struct bedPlusLabel)); + if (tg->visibility == tvPack || tg->visibility == tvFull) + item->label = cloneString(func(item->bed.name)); + slAddHead(&itemList, item); + } +sqlFreeResult(&sr); +hFreeConn(&conn); +slReverse(&itemList); +slSort(&itemList, bedCmp); +tg->items = itemList; +} + +static void bedPlusLabelDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, + double scale, MgFont *font, Color color, enum trackVisibility vis) +/* Draw a single bed item at position. If vis is full, draw the associated label to the left + * of the item. */ +{ +struct bedPlusLabel *bpl = item; +struct bed *bed = item; +int heightPer = tg->heightPer; +int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; +int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; +int w; + +if (tg->itemColor != NULL) + color = tg->itemColor(tg, bed, hvg); + +w = x2-x1; +if (w < 1) + w = 1; +hvGfxBox(hvg, x1, y, w, heightPer, color); + +// In full mode, draw bpl->label to the left of item: +if (vis == tvFull) + { + int textWidth = mgFontStringWidth(font, bpl->label); + hvGfxTextRight(hvg, x1-textWidth-2, y, textWidth, heightPer, MG_BLACK, font, bpl->label); + } +} + +static void bedPlusLabelMapItem(struct track *tg, struct hvGfx *hvg, void *item, + char *itemName, char *mapItemName, int start, int end, + int x, int y, int width, int height) +/* Special mouseover text from item->label. (derived from genericMapItem) */ +{ +// Don't bother if we are imageV2 and a dense child. +if(!theImgBox || tg->limitedVis != tvDense || !tdbIsCompositeChild(tg->tdb)) + { + struct bedPlusLabel *bpl = item;; + char *mouseOverText = isEmpty(bpl->label) ? bpl->bed.name : bpl->label; + mapBoxHc(hvg, start, end, x, y, width, height, tg->track, mapItemName, mouseOverText); + } +} + +static char *collapseRowsFromQuery(char *query, char *sep, int limit) +/* Return a string that is the concatenation of (up to limit) row[0]'s returned from query, + * separated by sep. Don't free the return value! */ +{ +static struct dyString *dy = NULL; +if (dy == NULL) + dy = dyStringNew(0); +dyStringClear(dy); +struct sqlConnection *conn = hAllocConn(database); +struct sqlResult *sr = sqlMustGetResult(conn, query); +int i = 0; +char **row = NULL; +while ((row = sqlNextRow(sr)) != NULL) + { + eraseTrailingSpaces(row[0]); + if (i != 0) + dyStringAppend(dy, sep); + dyStringAppend(dy, row[0]); + if (i == limit) + { + dyStringAppend(dy, " ..."); + break; + } + i++; + } + +sqlFreeResult(&sr); +hFreeConn(&conn); +return dy->string; +} +// end stuff shared by GAD, OMIM, DECIPHER, Superfamily + + char *lfMapNameFromExtra(struct track *tg, void *item) /* Return map name of item from extra field. */ { struct linkedFeatures *lf = item; return lf->extra; } #ifndef GBROWSE static struct simpleFeature *sfFromGenePred(struct genePred *gp, int grayIx) /* build a list of simpleFeature objects from a genePred */ { struct simpleFeature *sfList = NULL, *sf; unsigned *starts = gp->exonStarts; unsigned *ends = gp->exonEnds; int i, blockCount = gp->exonCount; @@ -4708,86 +4818,30 @@ char *name; char *proteinName; struct sqlConnection *conn = hAllocConn(database); char conditionStr[256]; struct bed *sw = item; // This is necessary because Ensembl kept changing their xref table definition sprintf(conditionStr, "transcript_name='%s'", sw->name); if (hTableExists(database, "ensGeneXref")) { proteinName = sqlGetField(database, "ensGeneXref", "translation_name", conditionStr); } else if (hTableExists(database, "ensemblXref2")) { - proteinName = sqlGetField(FALSE, "ensemblXref2", "translation_name", conditionStr); - } -else - {if (hTableExists(database, "ensemblXref")) - { - proteinName = sqlGetField(database, "ensemblXref", "translation_name", conditionStr); - } - else - { - if (hTableExists(database, "ensTranscript")) - { - proteinName = sqlGetField(database,"ensTranscript","translation_name",conditionStr); - } - else - { - if (hTableExists(database, "ensemblXref3")) - { - sprintf(conditionStr, "transcript='%s'", sw->name); - proteinName = sqlGetField(database, "ensemblXref3", "protein", conditionStr); - } - else - { - proteinName = cloneString(""); - } - } - } - } - -name = cloneString(proteinName); -hFreeConn(&conn); -/* -abbr(name, "000000"); -abbr(name, "00000"); -abbr(name, "0000"); -*/ -return(name); -} - -char *superfamilyMapName(struct track *tg, void *item) -/* Return map name of the track item (used by hgc). */ -{ -char *name; -char *proteinName; -struct sqlConnection *conn = hAllocConn(database); -char conditionStr[256]; - -struct bed *sw = item; - -// This is necessary because Ensembl kept changing their xref table definition -sprintf(conditionStr, "transcript_name='%s'", sw->name); -if (hTableExists(database, "ensGeneXref")) - { - proteinName = sqlGetField(database, "ensGeneXref", "translation_name", conditionStr); - } -else if (hTableExists(database, "ensemblXref2")) - { proteinName = sqlGetField(database, "ensemblXref2", "translation_name", conditionStr); } else { if (hTableExists(database, "ensemblXref")) { proteinName = sqlGetField(database, "ensemblXref", "translation_name", conditionStr); } else { if (hTableExists(database, "ensTranscript")) { proteinName = sqlGetField(database,"ensTranscript","translation_name",conditionStr); } else @@ -4799,448 +4853,143 @@ } else { proteinName = cloneString(""); } } } } name = cloneString(proteinName); hFreeConn(&conn); return(name); } -// assuming no more than 100 domains in a protein -char sfDesc[100][256]; -char sfBuffer[25600]; - -char *superfamilyNameLong(struct track *tg, void *item) +static char *superfamilyNameLong(char *name) /* Return domain names of an entry of a Superfamily track item, each item may have multiple names due to possibility of multiple domains. */ { -struct bed *sw = item; -struct sqlConnection *conn; -int sfCnt; -char *desc; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; -int i; - -conn = hAllocConn(database); -sprintf(query, - "select description from sfDescription where name='%s';", - sw->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -sfCnt = 0; -while (row != NULL) - { - desc = row[0]; - sprintf(sfDesc[sfCnt], "%s", desc); - - row = sqlNextRow(sr); - sfCnt++; - if (sfCnt >= 100) break; +safef(query, sizeof(query), "select description from sfDescription where name='%s';", name); +return collapseRowsFromQuery(query, "; ", 100); } -chp = sfBuffer; -for (i=0; i<sfCnt; i++) - { - if (i != 0) +static void superfamilyLoad(struct track *tg) +/* Load superfamily items; in addition to items, store long description for mouseover/full mode. */ { - sprintf(chp, "; "); - chp++;chp++; - } - sprintf(chp, "%s", sfDesc[i]); - chp = chp+strlen(sfDesc[i]); - } - -sqlFreeResult(&sr); -hFreeConn(&conn); - -return(sfBuffer); -} - -int superfamilyItemStart(struct track *tg, void *item) -/* Return start position of item. */ -{ -struct bed *bed = item; -return bed->chromStart; -} - -int superfamilyItemEnd(struct track *tg, void *item) -/* Return end position of item. */ -{ -struct bed *bed = item; -return bed->chromEnd; -} - -static void superfamilyDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ -{ -struct bed *bed = item; -char *sLong; -int heightPer = tg->heightPer; -int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; -int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; -int w; - -sLong = superfamilyNameLong(tg, item); -if (tg->itemColor != NULL) - color = tg->itemColor(tg, bed, hvg); -else - { - if (tg->colorShades) - color = tg->colorShades[grayInRange(bed->score, 0, 1000)]; - } -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, color); - - // special label processing for superfamily track, because long names provide - // important info on structures and functions - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sLong)-2, y, mgFontStringWidth(font, sLong), - heightPer, MG_BLACK, font, sLong); - } - if (tg->drawName && vis != tvSquish) - { - /* Clip here so that text will tend to be more visible... */ - char *s = tg->itemName(tg, bed); - w = x2-x1; - if (w > mgFontStringWidth(font, s)) - { - Color textColor = hvGfxContrastingColor(hvg, color); - hvGfxTextCentered(hvg, x1, y, w, heightPer, textColor, font, s); - } - } - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), sLong); - } -if (tg->subType == lfWithBarbs) - { - int dir = 0; - if (bed->strand[0] == '+') - dir = 1; - else if(bed->strand[0] == '-') - dir = -1; - if (dir != 0 && w > 2) - { - int midY = y + (heightPer>>1); - Color textColor = hvGfxContrastingColor(hvg, color); - clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, - dir, textColor, TRUE); - } - } -} - -static void superfamilyDraw(struct track *tg, int seqStart, int seqEnd, - struct hvGfx *hvg, int xOff, int yOff, int width, - MgFont *font, Color color, enum trackVisibility vis) -/* Draw superfamily items. */ -{ -if (!tg->drawItemAt) - errAbort("missing drawItemAt in track %s", tg->track); -genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width, - font, color, vis); +bedPlusLabelLoad(tg, superfamilyNameLong); } void superfamilyMethods(struct track *tg) /* Fill in methods for (simple) bed tracks. */ { -tg->drawItems = superfamilyDraw; -tg->drawItemAt = superfamilyDrawAt; +tg->loadItems = superfamilyLoad; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; tg->itemName = superfamilyName; -tg->mapItemName = superfamilyMapName; -tg->totalHeight = tgFixedTotalHeightNoOverflow; -tg->itemHeight = tgFixedItemHeight; -tg->itemStart = superfamilyItemStart; -tg->itemEnd = superfamilyItemEnd; -tg->drawName = FALSE; +tg->mapItemName = superfamilyName; +tg->nextPrevExon = simpleBedNextPrevEdge; } -struct hash *gdHash; - -/* reserve space no more than 20 unique gad disease entries */ -char gadDiseaseClassBuffer[2000]; - -/* reserve space no more than 20 unique decipher entries */ -char decipherBuffer[2000]; - -char *gadDiseaseClassList(struct track *tg, struct bed *item) +static char *gadDiseaseClassList(char *name) /* Return list of diseases associated with a GAD entry */ { -struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; -char *diseaseClassCode; - -int i=0; -conn = hAllocConn(database); - safef(query, sizeof(query), -"select distinct diseaseClassCode from gadAll where geneSymbol='%s' and association = 'Y' order by diseaseClassCode", -item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -/* show up to 20 max entries */ -chp = gadDiseaseClassBuffer; -while ((row != NULL) && i<20) - { - if (i != 0) - { - safef(chp, 2, ","); - chp++; - } - diseaseClassCode = row[0]; - - safef(chp, 100, "%s", diseaseClassCode); - chp = chp+strlen(diseaseClassCode); - row = sqlNextRow(sr); - i++; - } - -if ((i == 20) && (row != NULL)) - { - safef(chp, 4, " ..."); - chp++;chp++;chp++;chp++; - } - -*chp = '\0'; - -hFreeConn(&conn); -sqlFreeResult(&sr); -return(gadDiseaseClassBuffer); + "select distinct diseaseClassCode from gadAll " + "where geneSymbol='%s' and association = 'Y' order by diseaseClassCode", + name); +return collapseRowsFromQuery(query, ",", 20); } -/* reserve space no more than 100 unique gad disease entries */ -char gadBuffer[25600]; - -char *gadDiseaseList(struct track *tg, struct bed *item) +static char *gadDiseaseList(char *name) /* Return list of diseases associated with a GAD entry */ { -struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; -int i=0; - -conn = hAllocConn(database); - safef(query, sizeof(query), -"select distinct broadPhen from gadAll where geneSymbol='%s' and association = 'Y' order by broadPhen", item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -/* show up to 20 max entries */ -chp = gadBuffer; -while ((row != NULL) && i<20) - { - if (i != 0) - { - sprintf(chp, "; "); - chp++;chp++; - } - sprintf(chp, "%s", row[0]); - chp = chp+strlen(row[0]); - row = sqlNextRow(sr); - i++; + "select distinct broadPhen from gadAll where geneSymbol='%s' and association = 'Y' " + "order by broadPhen", name); +return collapseRowsFromQuery(query, "; ", 20); } -if ((i == 20) && (row != NULL)) +static void gadLoad(struct track *tg) +/* Load GAD items as bed + label (used for mouseover; different label in draw routine!) */ { - sprintf(chp, " ..."); - chp++;chp++;chp++;chp++; - } - -*chp = '\0'; - -hFreeConn(&conn); -sqlFreeResult(&sr); -return(gadBuffer); +bedPlusLabelLoad(tg, gadDiseaseList); } static void gadDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ +/* Draw a single GAD item at position with extra label in full mode. + * This is almost identical to bedPlusLabelDrawAt, but uses yet another function + * to derive extra text in full mode. */ { struct bed *bed = item; -char *sDiseases; -char *sDiseaseClasses; int heightPer = tg->heightPer; int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; int w; -sDiseases = gadDiseaseList(tg, item); -sDiseaseClasses = gadDiseaseClassList(tg, item); -if (tg->itemColor != NULL) - color = tg->itemColor(tg, bed, hvg); -else - { - if (tg->colorShades) - color = tg->colorShades[grayInRange(bed->score, 0, 1000)]; - } w = x2-x1; if (w < 1) w = 1; -if (color) - { hvGfxBox(hvg, x1, y, w, heightPer, color); if (vis == tvFull) { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sDiseaseClasses)-2, y, - mgFontStringWidth(font, sDiseaseClasses), - heightPer, MG_BLACK, font, sDiseaseClasses); - } - if (tg->drawName && vis != tvSquish) - { - /* Clip here so that text will tend to be more visible... */ - char *s = tg->itemName(tg, bed); - w = x2-x1; - if (w > mgFontStringWidth(font, s)) - { - Color textColor = hvGfxContrastingColor(hvg, color); - hvGfxTextCentered(hvg, x1, y, w, heightPer, textColor, font, s); - } - } - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), sDiseases); - } -if (tg->subType == lfWithBarbs) - { - int dir = 0; - if (bed->strand[0] == '+') - dir = 1; - else if(bed->strand[0] == '-') - dir = -1; - if (dir != 0 && w > 2) - { - int midY = y + (heightPer>>1); - Color textColor = hvGfxContrastingColor(hvg, color); - clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, - dir, textColor, TRUE); - } + // New text for label in full mode: + char *sDiseaseClasses = gadDiseaseClassList(bed->name); + int textWidth = mgFontStringWidth(font, sDiseaseClasses); + hvGfxTextRight(hvg, x1-textWidth-2, y, textWidth, heightPer, MG_BLACK, font, sDiseaseClasses); } } -char *decipherPhenotypeList(struct track *tg, char *name) +static char *decipherPhenotypeList(char *name) /* Return list of diseases associated with a DECIPHER entry */ { -struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; -int i=0; - -conn = hAllocConn(database); - safef(query,sizeof(query), "select distinct phenotype from decipherRaw where id='%s' order by phenotype", name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -/* show up to 20 max entries */ -chp = decipherBuffer; -while ((row != NULL) && i<20) - { - if (i != 0) - { - safef(chp, 3, "; "); - chp++;chp++; - } - safef(chp, 100, "%s", row[0]); - chp = chp+strlen(row[0]); - row = sqlNextRow(sr); - i++; - } - -if ((i == 20) && (row != NULL)) - { - safef(chp, 5, " ..."); - chp++;chp++;chp++;chp++; - } - -*chp = '\0'; - -hFreeConn(&conn); -sqlFreeResult(&sr); -return(decipherBuffer); +return collapseRowsFromQuery(query, "; ", 20); } void decipherLoad(struct track *tg) -/* Convert bed4 to linkedFeatures so we can have next "exon" arrows. */ -{ -struct sqlConnection *conn = hAllocConn(database); -struct linkedFeatures *lfList = NULL; -int rowOffset = 0; -struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); -char **row = NULL; -while ((row = sqlNextRow(sr)) != NULL) +/* Load DECIPHER items with extra labels from decipherPhenotypeList. */ { - struct bed *bed = bedLoad(row+rowOffset); - bed->score = 1000; - bed->strand[0] = '.'; - bed->thickStart = bed->chromStart; - bed->thickEnd = bed->chromEnd; - struct linkedFeatures *lf = bedMungToLinkedFeatures(&bed, tg->tdb, 4, 0, 1000, FALSE); - lf->extra = cloneString(decipherPhenotypeList(tg, lf->name)); - slAddHead(&lfList, lf); - } -sqlFreeResult(&sr); -hFreeConn(&conn); -slReverse(&lfList); -slSort(&lfList, linkedFeaturesCmp); -tg->items = lfList; +bedPlusLabelLoad(tg, decipherPhenotypeList); } Color decipherColor(struct track *tg, void *item, struct hvGfx *hvg) /* Return color to draw DECIPHER entry */ { -struct linkedFeatures *lf = item; +struct bed *bed = item; int col = tg->ixColor; struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr; char **row; char query[256]; char cond_str[256]; char *decipherId = NULL; /* color scheme: RED: If the entry is a deletion (mean ratio < 0) BLUE: If the entry is a duplication (mean ratio > 0) */ -safef(cond_str, sizeof(cond_str),"name='%s' ", lf->name); +safef(cond_str, sizeof(cond_str),"name='%s' ", bed->name); decipherId = sqlGetField(database, "decipher", "name", cond_str); if (decipherId != NULL) { if (hTableExists(database, "decipherRaw")) { safef(query, sizeof(query), "select mean_ratio > 0 from decipherRaw where id = '%s'", decipherId); sr = sqlGetResult(conn, query); if ((row = sqlNextRow(sr)) != NULL) { if (sameWord(row[0], "1")) { col = MG_BLUE; } else { @@ -5256,113 +5005,60 @@ sr = sqlGetResult(conn, query); if ((row = sqlNextRow(sr)) != NULL) { if (sameWord(row[0], "1")) { col = MG_GRAY; } } sqlFreeResult(&sr); } } hFreeConn(&conn); return(col); } -static void decipherDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ -{ -struct linkedFeatures *lf = item; -char *sPhenotypes = lf->extra; -int heightPer = tg->heightPer; -int x1 = round((double)((int)lf->start-winStart)*scale) + xOff; -int x2 = round((double)((int)lf->end-winStart)*scale) + xOff; -int w; - -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, decipherColor(tg, item, hvg)); - - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sPhenotypes)-2, y, - mgFontStringWidth(font, sPhenotypes), - heightPer, MG_BLACK, font, sPhenotypes); - } - if (tg->drawName && vis != tvSquish) - { - /* Clip here so that text will tend to be more visible... */ - char *s = tg->itemName(tg, item); - w = x2-x1; - if (w > mgFontStringWidth(font, s)) - { - Color textColor = hvGfxContrastingColor(hvg, color); - hvGfxTextCentered(hvg, x1, y, w, heightPer, textColor, font, s); - } - } - } -} - -void decipherMapItem(struct track *tg, struct hvGfx *hvg, void *item, - char *itemName, char *mapItemName, int start, int end, - int x, int y, int width, int height) -/* Special mouseover text from lf->extra (phenotype list). */ -{ -// Don't bother if we are imageV2 and a dense child. -if(!theImgBox || tg->limitedVis != tvDense || !tdbIsCompositeChild(tg->tdb)) - { - struct linkedFeatures *lf = item; - char *directUrl = trackDbSetting(tg->tdb, "directUrl"); - boolean withHgsid = (trackDbSetting(tg->tdb, "hgsid") != NULL); - char *phenotypes = lf->extra; - char *mouseOverText = isEmpty(phenotypes) ? lf->name : phenotypes; - mapBoxHgcOrHgGene(hvg, start, end, x, y, width, height, tg->track, - mapItemName, mouseOverText, directUrl, withHgsid, NULL); - } -} - void decipherMethods(struct track *tg) /* Methods for DECIPHER track. */ { -linkedFeaturesMethods(tg); tg->loadItems = decipherLoad; -tg->mapItem = decipherMapItem; tg->itemColor = decipherColor; -tg->drawItemAt = decipherDrawAt; +tg->itemNameColor = decipherColor; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } char *emptyName(struct track *tg, void *item) /* Return name of item. */ { return(""); } void rdmrMethods(struct track *tg) /* Methods for R-DMR track. */ { tg->itemName = emptyName; } void gadMethods(struct track *tg) /* Methods for GAD track. */ { +tg->loadItems = gadLoad; tg->drawItemAt = gadDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } void rgdQtlDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a single rgdQtl item at position. */ { struct bed *bed = item; struct trackDb *tdb = tg->tdb; if (tg->itemColor != NULL) color = tg->itemColor(tg, bed, hvg); else if (tg->colorShades) { int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0")); @@ -11017,127 +10713,75 @@ tg->mapItemName = protVarMapName; tg->nextItemButtonable = TRUE; tg->nextPrevItem = linkedFeaturesLabelNextPrevItem; } void oregannoMethods (struct track *tg) /* load so can allow filtering on type */ { tg->loadItems = loadOreganno; tg->itemColor = oregannoColor; tg->itemNameColor = oregannoColor; tg->nextItemButtonable = TRUE; tg->nextPrevItem = linkedFeaturesLabelNextPrevItem; } -/* reserve space no more than 20 unique OMIM entries */ -char omimGene2Buffer[21 * OMIM_MAX_DESC_LEN]; -char *omimGene2DisorderList(struct track *tg, struct bed *item) -/* Return list of disorders associated with a OMIM entry */ +static char *omimGene2DisorderList(char *name) +/* Return list of disorders associated with a OMIM entry. Do not free result! */ { +static struct dyString *dy = NULL; struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -int i; -// initialize omimGene2Buffer -omimGene2Buffer[0]='\0'; +if (dy == NULL) + dy = dyStringNew(0); +dyStringClear(dy); // get gene symbol(s) first - conn = hAllocConn(database); safef(query,sizeof(query), - "select geneSymbol from omimGeneMap where omimId =%s", item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -if (row != NULL) - { - safecat(omimGene2Buffer, sizeof(omimGene2Buffer), row[0]); - } - -sqlFreeResult(&sr); + "select geneSymbol from omimGeneMap where omimId =%s", name); +char buf[256]; +char *ret = sqlQuickQuery(conn, query, buf, sizeof(buf)); +if (isNotEmpty(ret)) + dyStringAppend(dy, ret); safef(query,sizeof(query), - "select distinct disorder from omimDisorderMap, omimGene2 where name='%s' and name=cast(omimId as char) order by disorder", item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -if (row == NULL) - { - hFreeConn(&conn); - sqlFreeResult(&sr); - return(omimGene2Buffer); - } -else + "select distinct disorder from omimDisorderMap, omimGene2 where name='%s' and name=cast(omimId as char) order by disorder", name); +char *disorders = collapseRowsFromQuery(query, "; ", 20); +if (isNotEmpty(disorders)) { - safecat(omimGene2Buffer, sizeof(omimGene2Buffer), "; disorder(s): "); + dyStringAppend(dy, "; disorder(s): "); + dyStringAppend(dy, disorders); } - -/* show up to 20 max entries */ -i=0; -while ((row != NULL) && i<20) - { - /* omimDisorderMap disorder field some times have trailing blanks. */ - eraseTrailingSpaces(row[0]); - if (i != 0) - { - safecat(omimGene2Buffer, sizeof(omimGene2Buffer), "; "); - } - safecat(omimGene2Buffer, sizeof(omimGene2Buffer), row[0]); - - row = sqlNextRow(sr); - i++; - } - -if (i == 0) errAbort("in omimGene2DisorderList(), no entry found in omimDisorderMap"); - -if ((i == 20) && (row != NULL)) - { - safecat(omimGene2Buffer, sizeof(omimGene2Buffer), " ..."); - } - hFreeConn(&conn); -sqlFreeResult(&sr); -return(omimGene2Buffer); +return(dy->string); } char *getDisorderClass(char *omimId) +/* Look up phenotypeClass for omimId, for filtering items. Don't free result! */ { -struct sqlConnection *conn; +static char answer[256]; +struct sqlConnection *conn = hAllocConn(database); char query[256]; -struct sqlResult *sr; -char **row; -char *answer; -conn = hAllocConn(database); safef(query,sizeof(query), "select phenotypeClass from omimDisorderPhenotype where omimId =%s", omimId); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); -if (row != NULL) - { - answer = strdup(row[0]); - } -else - { - answer = strdup("0"); - } - +char *ret = sqlQuickQuery(conn, query, answer, sizeof(answer)); +if (ret == NULL) + safecpy(answer, sizeof(answer), "0"); hFreeConn(&conn); -sqlFreeResult(&sr); return(answer); } boolean doThisOmimEntry(struct track *tg, char *omimId) /* check if the specific class of this OMIM entry is selected by the user */ { char *disorderClass = NULL; boolean doIt; char labelName[255]; boolean doClass1 = FALSE; boolean doClass2 = FALSE; boolean doClass3 = FALSE; boolean doClass4 = FALSE; boolean doOthers = FALSE; @@ -11175,110 +10819,52 @@ } } disorderClass = getDisorderClass(omimId); doIt = FALSE; doIt = doIt || (doClass1 && sameWord(disorderClass, "1")) ; doIt = doIt || (doClass2 && sameWord(disorderClass, "2")) ; doIt = doIt || (doClass3 && sameWord(disorderClass, "3")) ; doIt = doIt || (doClass4 && sameWord(disorderClass, "4")) ; doIt = doIt || (doOthers && sameWord(disorderClass, "0")) ; return(doIt); } -static void omimGene2DrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ -{ -struct bed *bed = item; -char *sPhenotypes; -int heightPer = tg->heightPer; -int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; -int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; -int w; - -sPhenotypes = omimGene2DisorderList(tg, item); -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, color); - - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sPhenotypes)-2, y, - mgFontStringWidth(font, sPhenotypes), - heightPer, MG_BLACK, font, sPhenotypes); - } - if (vis != tvDense) - { - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), sPhenotypes); - /* enable display of disorder info when user mouse over item name */ - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1-mgFontStringWidth(font, bed->name)-2, y, - mgFontStringWidth(font, bed->name), heightPer, - tg->track, tg->mapItemName(tg, bed), sPhenotypes); - } - } - -if (tg->subType == lfWithBarbs) - { - int dir = 0; - if (bed->strand[0] == '+') - dir = 1; - else if(bed->strand[0] == '-') - dir = -1; - if (dir != 0 && w > 2) +static void omimFilter(struct track *tg) +/* Filter the already-loaded items in the omimGene2 or the omimLocation track */ { - int midY = y + (heightPer>>1); - Color textColor = hvGfxContrastingColor(hvg, color); - clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, - dir, textColor, TRUE); - } - } -} - -void omimBedLoad(struct track *tg) -/* Load the items in the gmimeGene2 or the omimLocation track */ -{ -struct bed *bed, *list = NULL; -struct sqlConnection *conn = hAllocConn(database); -struct sqlResult *sr; -char **row; -int rowOffset; - -sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); -while ((row = sqlNextRow(sr)) != NULL) +struct bed *bed, *nextBed = NULL, *list = NULL; +for (bed = tg->items; bed != NULL; bed = nextBed) { - bed = bedLoadN(row+rowOffset, 4); - + nextBed = bed->next; /* check if user has selected the specific class for this OMIM entry */ if (doThisOmimEntry(tg, bed->name)) - { slAddHead(&list, bed); } - } -sqlFreeResult(&sr); -hFreeConn(&conn); slReverse(&list); tg->items = list; } +static void omimGene2Load(struct track *tg) +/* Load and filter omimGene2 items, storing long label from omimGene2DisorderList. */ +{ +bedPlusLabelLoad(tg, omimGene2DisorderList); +omimFilter(tg); +} + Color omimGene2Color(struct track *tg, void *item, struct hvGfx *hvg) /* set the color for omimLocation track items */ { struct bed *el = item; char *omimId; char *phenClass; char query[256]; struct sqlResult *sr; char **row; struct sqlConnection *conn = hAllocConn(database); safef(query, sizeof(query), "select omimId, phenotypeClass from omimDisorderPhenotype where omimId=%s", el->name); sr = sqlMustGetResult(conn, query); @@ -11313,154 +10899,98 @@ { // set to orange for class 1 sqlFreeResult(&sr); return hvGfxFindColorIx(hvg, 200, 0, 200); } else { // set to purplish color for phenClass 4 sqlFreeResult(&sr); return hvGfxFindColorIx(hvg, 200, 100, 100); } } } void omimGene2Methods (struct track *tg) +/* Methods for version 2 of OMIM Genes track. */ { +tg->loadItems = omimGene2Load; tg->itemColor = omimGene2Color; tg->itemNameColor = omimGene2Color; -tg->drawItemAt = omimGene2DrawAt; -tg->loadItems = omimBedLoad; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } -char omimAvSnpBuffer[OMIM_MAX_DESC_LEN]; -char *omimAvSnpAaReplacement(struct track *tg, struct bed *item) -/* Return replacement string associated with a OMIM AV entry */ +static char *omimAvSnpAaReplacement(char *name) +/* Return replacement string associated with a OMIM AV (Allelic Variant) entry */ { +static char omimAvSnpBuffer[256]; struct sqlConnection *conn; char query[256]; struct sqlResult *sr; char **row; -char *chp; omimAvSnpBuffer[0] = '\0'; conn = hAllocConn(database); safef(query,sizeof(query), - "select replStr, dbSnpId, description from omimAvRepl where avId='%s'", item->name); + "select replStr, dbSnpId, description from omimAvRepl where avId='%s'", name); sr = sqlMustGetResult(conn, query); row = sqlNextRow(sr); -chp = omimAvSnpBuffer; if (row != NULL) { safef(omimAvSnpBuffer, sizeof(omimAvSnpBuffer), "%s, %s: %s", row[0], row[1], row[2]); } hFreeConn(&conn); sqlFreeResult(&sr); return(omimAvSnpBuffer); } -static void omimAvSnpDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a omimAvSnp item at position. */ +static void omimAvSnpLoad(struct track *tg) +/* Load OMIM AV items, storing long label from omimAvSnpAaReplacement. */ { -struct bed *bed = item; -char *itemDesc; -int heightPer = tg->heightPer; -int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; -int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; -int w; - -itemDesc = omimAvSnpAaReplacement(tg, item); -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, color); - - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, itemDesc)-2, y, - mgFontStringWidth(font, itemDesc), - heightPer, MG_BLACK, font, itemDesc); - } - - if (vis != tvDense) - { - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), itemDesc); - /* enable display of disorder info when user mouse over item name */ - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1-mgFontStringWidth(font, bed->name)-2, y, - mgFontStringWidth(font, bed->name), heightPer, - tg->track, tg->mapItemName(tg, bed), itemDesc); - } - } - -if (tg->subType == lfWithBarbs) - { - int dir = 0; - if (bed->strand[0] == '+') - dir = 1; - else if(bed->strand[0] == '-') - dir = -1; - if (dir != 0 && w > 2) - { - int midY = y + (heightPer>>1); - Color textColor = hvGfxContrastingColor(hvg, color); - clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, - dir, textColor, TRUE); - } - } +bedPlusLabelLoad(tg, omimAvSnpAaReplacement); } void omimAvSnpMethods (struct track *tg) +/* Methods for OMIM AV (Allelic Variant) SNPs. */ { -tg->drawItemAt = omimAvSnpDrawAt; +tg->loadItems = omimAvSnpLoad; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } -char omimLocationBuffer[OMIM_MAX_DESC_LEN*2]; -char *omimLocationDescription(struct track *tg, struct bed *item) +static char *omimLocationDescription(char *name) /* Return description of an OMIM entry */ { +static char omimLocationBuffer[512]; struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; omimLocationBuffer[0] = '\0'; conn = hAllocConn(database); safef(query,sizeof(query), - "select concat(title1, ' ', title2) from omimGeneMap where omimId=%s", item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -chp = omimLocationBuffer; -if (row != NULL) - { - safef(omimLocationBuffer, sizeof(omimLocationBuffer), "%s", row[0]); - } - + "select concat(title1, ' ', title2) from omimGeneMap where omimId=%s", name); +(void)sqlQuickQuery(conn, query, omimLocationBuffer, sizeof(omimLocationBuffer)); hFreeConn(&conn); -sqlFreeResult(&sr); return(omimLocationBuffer); } Color omimLocationColor(struct track *tg, void *item, struct hvGfx *hvg) /* set the color for omimLocation track items */ { struct bed *el = item; char *omimId; char *phenClass; char query[256]; struct sqlResult *sr; char **row; struct sqlConnection *conn = hAllocConn(database); @@ -11504,68 +11034,45 @@ sqlFreeResult(&sr); return hvGfxFindColorIx(hvg, 200, 0, 200); } else { // set to purplish color for phenClass 4 sqlFreeResult(&sr); return hvGfxFindColorIx(hvg, 200, 100, 100); } } } } } -static void omimLocationDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ +static void omimLocationLoad(struct track *tg) +/* Load and filter OMIM Loci items, storing long label from omimLocationDescription. */ { -struct bed *bed = item; -char *omimTitle; -int heightPer = tg->heightPer; -int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; -int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; -int w; - -omimTitle = omimLocationDescription(tg, item); -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, omimLocationColor(tg, item, hvg)); - - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, omimTitle)-2, y, - mgFontStringWidth(font, omimTitle), - heightPer, MG_BLACK, font, omimTitle); - } - - if (vis != tvDense) - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), omimTitle); - } +bedPlusLabelLoad(tg, omimLocationDescription); +omimFilter(tg); } void omimLocationMethods (struct track *tg) +/* Methods for OMIM Loci (Non-Gene Entry Cytogenetic Locations). */ { -tg->drawItemAt = omimLocationDrawAt; +tg->loadItems = omimLocationLoad; tg->itemColor = omimLocationColor; -tg->loadItems = omimBedLoad; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } char *omimGeneName(struct track *tg, void *item) /* set name for omimGene track */ { struct bed *el = item; char query[256]; struct sqlConnection *conn = hAllocConn(database); char *geneLabel = NULL; char *omimGeneLabel = cartUsualString(cart, "omimGene.label", "OMIM ID"); if (sameWord(omimGeneLabel, "OMIM ID")) { geneLabel = el->name; @@ -11628,135 +11135,56 @@ /* set the color to red if the entry is listed in morbidmap */ safef(query, sizeof(query), "select geneSymbols from omimMorbidMap where omimId=%s", el->name); geneSymbols = sqlQuickString(conn, query); hFreeConn(&conn); if (geneSymbols != NULL) { return hvGfxFindColorIx(hvg, 255, 0, 0); } else { return hvGfxFindColorIx(hvg, 0, 0, 200); } } -/* reserve space no more than 20 unique OMIM entries */ -char omimGeneBuffer[20 * OMIM_MAX_DESC_LEN]; - -char *omimGeneDiseaseList(struct track *tg, struct bed *item) +static char *omimGeneDiseaseList(char *name) /* Return list of diseases associated with a OMIM entry */ { -struct sqlConnection *conn; char query[256]; -struct sqlResult *sr; -char **row; -char *chp; -int i=0; - -conn = hAllocConn(database); - safef(query,sizeof(query), - "select distinct description from omimMorbidMap, omimGene where name='%s' and name=cast(omimId as char) order by description", item->name); -sr = sqlMustGetResult(conn, query); -row = sqlNextRow(sr); - -/* show up to 20 max entries */ -chp = omimGeneBuffer; -while ((row != NULL) && i<20) - { - /* omimMorbidMap description field some times have trailing blanks. */ - eraseTrailingSpaces(row[0]); - if (i != 0) - { - safef(chp, 3, "; "); - chp++;chp++; - } - safecpy(chp, OMIM_MAX_DESC_LEN, row[0]); - chp = chp+strlen(row[0]); - row = sqlNextRow(sr); - i++; + "select distinct description from omimMorbidMap, omimGene " + "where name='%s' and name=cast(omimId as char) order by description", name); +return collapseRowsFromQuery(query, "; ", 20); } -if ((i == 20) && (row != NULL)) +static void omimGeneLoad(struct track *tg) +/* Load OMIM Genes, storing long label from omimGeneDiseaseList. */ { - safef(chp, 5, " ..."); - chp++;chp++;chp++;chp++; - } - -*chp = '\0'; - -hFreeConn(&conn); -sqlFreeResult(&sr); -return(omimGeneBuffer); -} - -static void omimGeneDrawAt(struct track *tg, void *item, - struct hvGfx *hvg, int xOff, int y, - double scale, MgFont *font, Color color, enum trackVisibility vis) -/* Draw a single superfamily item at position. */ -{ -struct bed *bed = item; -char *sPhenotypes; -int heightPer = tg->heightPer; -int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff; -int x2 = round((double)((int)bed->chromEnd-winStart)*scale) + xOff; -int w; - -sPhenotypes = omimGeneDiseaseList(tg, item); -w = x2-x1; -if (w < 1) - w = 1; -if (color) - { - hvGfxBox(hvg, x1, y, w, heightPer, omimGeneColor(tg, item, hvg)); - - if (vis == tvFull) - { - hvGfxTextRight(hvg, x1-mgFontStringWidth(font, sPhenotypes)-2, y, - mgFontStringWidth(font, sPhenotypes), - heightPer, MG_BLACK, font, sPhenotypes); - } - - if (vis != tvDense) - mapBoxHc(hvg, bed->chromStart, bed->chromEnd, x1, y, x2 - x1, heightPer, - tg->track, tg->mapItemName(tg, bed), sPhenotypes); - } - -if (tg->subType == lfWithBarbs) - { - int dir = 0; - if (bed->strand[0] == '+') - dir = 1; - else if(bed->strand[0] == '-') - dir = -1; - if (dir != 0 && w > 2) - { - int midY = y + (heightPer>>1); - Color textColor = hvGfxContrastingColor(hvg, color); - clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing, - dir, textColor, TRUE); - } - } +bedPlusLabelLoad(tg, omimGeneDiseaseList); } void omimGeneMethods (struct track *tg) +/* Methods for original OMIM Genes track. */ { +tg->loadItems = omimGeneLoad; tg->itemColor = omimGeneColor; tg->itemNameColor = omimGeneColor; tg->itemName = omimGeneName; -tg->drawItemAt = omimGeneDrawAt; +tg->drawItemAt = bedPlusLabelDrawAt; +tg->mapItem = bedPlusLabelMapItem; +tg->nextPrevExon = simpleBedNextPrevEdge; } Color restColor(struct track *tg, void *item, struct hvGfx *hvg) /* set the color for REST track items */ { struct bed *el = item; if (strstr(el->name, "ESC_only")) { return tg->ixAltColor; } else { return tg->ixColor; }