d6039d2a5b455ea12543034b5f959886d6d7e51f kate Thu Mar 24 20:45:39 2016 -0700 1. Add -log option to bedScore. 2. Score GTEx gene track bed files based on total median expression level across all tissues, for use in dense mode (gray-scale based on total expression), and display score on details page. 3. Implement viz for squished mode -- show color of highest expressed tissue if over threshold, and show tissue name in mouseover. refs #15645 diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c index caa71a4..13dacfa 100644 --- src/hg/hgTracks/gtexTracks.c +++ src/hg/hgTracks/gtexTracks.c @@ -108,45 +108,62 @@ int getTissueCount(char *version) /* Get and cache the number of tissues in GTEx tissue table */ { static int tissueCount = 0; if (!tissueCount) tissueCount = slCount(getTissues(version)); return tissueCount; } char *getTissueName(int id, char *version) /* Get tissue name from id, cacheing */ { static char **tissueNames = NULL; - struct gtexTissue *tissue; int count = getTissueCount(version); if (!tissueNames) { struct gtexTissue *tissues = getTissues(version); AllocArray(tissueNames, count); for (tissue = tissues; tissue != NULL; tissue = tissue->next) tissueNames[tissue->id] = cloneString(tissue->name); } if (id >= count) errAbort("GTEx tissue table problem: can't find id %d\n", id); return tissueNames[id]; } +char *getTissueDescription(int id, char *version) +/* Get tissue description from id, cacheing */ +{ +static char **tissueDescriptions = NULL; +struct gtexTissue *tissue; +int count = getTissueCount(version); +if (!tissueDescriptions) + { + struct gtexTissue *tissues = getTissues(version); + AllocArray(tissueDescriptions, count); + for (tissue = tissues; tissue != NULL; tissue = tissue->next) + tissueDescriptions[tissue->id] = cloneString(tissue->description); + } +if (id >= count) + errAbort("GTEx tissue table problem: can't find id %d\n", id); +return tissueDescriptions[id]; +} + struct rgbColor *getGtexTissueColors(char *version) /* Get RGB colors from tissue table */ { struct gtexTissue *tissues = getTissues(version); struct gtexTissue *tissue = NULL; int count = slCount(tissues); struct rgbColor *colors; AllocArray(colors, count); int i = 0; for (tissue = tissues; tissue != NULL; tissue = tissue->next) { // TODO: reconcile colors[i] = (struct rgbColor){.r=COLOR_32_BLUE(tissue->color), .g=COLOR_32_GREEN(tissue->color), .b=COLOR_32_RED(tissue->color)}; //colors[i] = mgColorIxToRgb(NULL, tissue->color); i++; @@ -276,33 +293,75 @@ static int filteredTissueCount(struct track *tg) /* Count of tissues to display */ { struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; return hashNumEntries(extras->tissueFilter); } static boolean filterTissue(struct track *tg, char *name) /* Does tissue pass filter */ { struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; return (hashLookup(extras->tissueFilter, name) != NULL); } +static int maxTissueForGene(struct gtexGeneBed *geneBed) +/* Return id of highest expressed tissue for gene, if significantly higher than median. + * If none are over threshold, return -1 */ +{ +double maxScore = 0.0, expScore; +double totalScore = 0.0; +int maxNum = 0, i; +int expCount = geneBed->expCount; +for (i=0; iexpScores[i]; + if (expScore > maxScore) + { + maxScore = max(maxScore, expScore); + maxNum = i; + } + totalScore += expScore; + } +// threshold to consider this gene tissue specific -- a tissue contributes > 10% to +// total expression level +//uglyf("gene=%s maxScore=%0.2f totalScore=%0.2f ", geneBed->name, maxScore, totalScore); +if (totalScore < 1 || maxScore <= totalScore * .1) + return -1; +return maxNum; +} + +static Color gtexGeneItemColor(struct track *tg, void *item, struct hvGfx *hvg) +/* A bit of tissue-specific coloring in squish mode only, on geneBed item */ +{ +struct gtexGeneBed *geneBed = (struct gtexGeneBed *)item; +int id = maxTissueForGene(geneBed); +if (id < 0) + return MG_BLACK; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +//uglyf("COLOR maxNum=%d
", maxNum); +struct rgbColor color = extras->colors[id]; +return hvGfxFindColorIx(hvg, color.r, color.g, color.b); +} + static void gtexGeneLoadItems(struct track *tg) /* Load method for track items */ { +if (tg->visibility == tvSquish || tg->limitedVis == tvSquish) + tg->itemColor = gtexGeneItemColor; + /* Get track UI info */ struct gtexGeneExtras *extras; AllocVar(extras); tg->extraUiData = extras; /* Get version info from track table name */ extras->version = gtexVersionSuffix(tg->table); extras->doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, GTEX_LOG_TRANSFORM_DEFAULT); char *samples = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_SAMPLES, GTEX_SAMPLES_DEFAULT); extras->graphType = cloneString(samples); if (sameString(samples, GTEX_SAMPLES_COMPARE_SEX)) extras->isComparison = TRUE; char *comparison = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COMPARISON_DISPLAY, @@ -540,34 +599,35 @@ } double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT); double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; return valToClippedHeight(maxExp, maxMedian, viewMax, gtexMaxGraphHeight(), extras->doLogTransform); } static void gtexGeneDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw tissue expression bar graph over gene model. Optionally, draw a second graph under gene, to compare sample sets */ { struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; struct gtexGeneBed *geneBed = geneInfo->geneBed; -// Color in dense mode using geneClass +// Color in squish mode using geneClass Color statusColor = getGeneClassColor(hvg, geneBed); if (vis != tvFull && vis != tvPack) { +uglyf("
drawAt %s\n", geneBed->name); bedDrawSimpleAt(tg, geneBed, hvg, xOff, y, scale, font, statusColor, vis); return; } int heightPer = tg->heightPer; int graphX = gtexGraphX(geneBed); if (graphX < 0) return; // draw gene model int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); int yZero = topGraphHeight + y - 1; // yZero is bottom of graph int yGene = yZero + gtexGeneMargin() - 1; tg->heightPer = gtexGeneModelHeight(extras) + 1; @@ -684,31 +744,31 @@ extras->doLogTransform); if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX)) hvGfxBox(hvg, x1, yZero, barWidth, height, fillColorIx); else hvGfxOutlinedBox(hvg, x1, yZero, barWidth, height, fillColorIx, lineColorIx); // mark clipped bar with magenta tip if (!extras->doLogTransform && expScore > viewMax) hvGfxBox(hvg, x1, yZero + height, barWidth, 1, clipColor); x1 = x1 + barWidth + graphPadding; } } static int gtexGeneItemHeightOptionalMax(struct track *tg, void *item, boolean isMax) { if (tg->visibility == tvSquish || tg->visibility == tvDense) - return 0; + return tgFixedItemHeight(tg, item); struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; if (isMax) { int extra = 0; if (((struct gtexGeneExtras *)tg->extraUiData)->isComparison) extra = gtexMaxGraphHeight() + 2; return gtexMaxGraphHeight() + gtexGeneMargin() + gtexGeneModelHeight(extras) + extra; } if (item == NULL) return 0; struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; if (geneInfo->height != 0) return geneInfo->height; int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); @@ -742,38 +802,49 @@ { static char buf[128]; safef(buf, sizeof(buf), "%s (%.1f %s%s%sRPKM)", tissue->description, doLogTransform ? log10(expScore+1.0) : expScore, qualifier != NULL ? qualifier : "", qualifier != NULL ? " " : "", doLogTransform ? "log " : ""); return buf; } static void gtexGeneMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* Create a map box on gene model and label, and one for each tissue (bar in the graph) in * pack or full mode. Just single map for squish/dense modes */ { -if (tg->visibility == tvDense || tg->visibility == tvSquish) +if (tg->visibility == tvDense) { genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height); return; } struct gtexGeneInfo *geneInfo = item; -struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; struct gtexGeneBed *geneBed = geneInfo->geneBed; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (tg->visibility == tvSquish) + { + int tisId = maxTissueForGene(geneBed); + char *maxTissue = ""; + if (tisId > 1) + maxTissue = getTissueDescription(tisId, extras->version); + char buf[128]; + safef(buf, sizeof buf, "%s %s%s", geneBed->name, tisId > 0 ? "+":"", maxTissue); + mapBoxHc(hvg, start, end, x, y, width, height, tg->track, mapItemName, buf); + return; + } int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); // label int yZero = topGraphHeight + y - 1; // yZero is bottom of graph //int yGene = yZero + gtexGeneMargin() - 1; int x1 = insideX; // add maps to tissue bars in expresion graph struct gtexTissue *tissues = getTissues(extras->version); struct gtexTissue *tissue = NULL; int barWidth = gtexBarWidth(); int padding = gtexGraphPadding(); double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; int graphX = gtexGraphX(geneBed);