1bd7f92d8aab55d8344619031c510ba8ad6b92fd kate Fri Nov 20 04:41:21 2015 -0800 Add map boxes with mouseover showing gene description to labe and gene model. Still needs some work on extent. refs #15645 diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c index f6fbbbc..19197c0 100644 --- src/hg/hgTracks/gtexTracks.c +++ src/hg/hgTracks/gtexTracks.c @@ -16,30 +16,31 @@ #include "spaceSaver.h" // NOTE: Sections to change for multi-region (vertical slice) display // are marked with #ifdef MULTI_REGION. WARNING: These sections // are a bit out-of-date (refer to #ifndef MULTI code when integrating) struct gtexGeneExtras /* Track info */ { double maxMedian; /* Maximum median rpkm for all tissues */ boolean isComparison; /* Comparison of two sample sets (e.g. male/female). */ boolean isDifference; /* True if comparison is shown as a single difference graph. False if displayed as two graphs, one oriented downward */ char *graphType; /* Additional info about graph (e.g. type of comparison graph */ struct rgbColor *colors; /* Color palette for tissues */ + boolean doLogTransform; /* Log10(x+1) */ }; struct gtexGeneInfo /* GTEx gene model, names, and expression medians */ { struct gtexGeneInfo *next; /* Next in singly linked list */ struct gtexGeneBed *geneBed;/* Gene name, id, canonical transcript, exp count and medians from BED table */ struct genePred *geneModel; /* Gene structure from model table */ double *medians1; /* Computed medians */ double *medians2; /* Computed medians for comparison (inverse) graph */ int height; /* Item height in pixels */ }; /***********************************************/ @@ -244,30 +245,32 @@ else { // TODO: compute median for single graph based on filtering of sample set } } static int gtexGeneItemHeight(struct track *tg, void *item); static void gtexGeneLoadItems(struct track *tg) /* Load method for track items */ { /* Get track UI info */ struct gtexGeneExtras *extras; AllocVar(extras); tg->extraUiData = extras; +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, GTEX_COMPARISON_DEFAULT); extras->isDifference = sameString(comparison, GTEX_COMPARISON_DIFF) ? TRUE : FALSE; extras->maxMedian = gtexMaxMedianScore(NULL); /* Get geneModels in range */ //TODO: version the table name, move to lib char *modelTable = "gtexGeneModel"; struct hash *modelHash = loadGeneModels(modelTable); @@ -429,77 +432,75 @@ useMax = maxView; if (val > maxView) useVal = maxView; } return valToHeight(useVal, useMax, gtexMaxGraphHeight(), doLogTransform); } static void drawGraphBase(struct hvGfx *hvg, int x, int y, struct gtexGeneInfo *geneInfo) /* Draw faint line under graph to delineate extent when bars are missing (tissue w/ 0 expression) */ { Color lightGray = MAKECOLOR_32(0xD1, 0xD1, 0xD1); int graphWidth = gtexGraphWidth(geneInfo); hvGfxBox(hvg, x, y, graphWidth, 1, lightGray); } -static int gtexGeneGraphHeight(struct track *tg, struct gtexGeneInfo *geneInfo, - boolean doLogTransform, boolean doTop) +static int gtexGeneGraphHeight(struct track *tg, struct gtexGeneInfo *geneInfo, boolean doTop) /* Determine height in pixels of graph. This will be the box for tissue with highest expression If doTop is false, compute height of bottom graph of comparison */ { struct gtexGeneBed *geneBed = geneInfo->geneBed; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; int i; double maxExp = 0.0; int expCount = geneBed->expCount; double expScore; for (i=0; imedians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); else expScore = geneInfo->medians2[i]; maxExp = max(maxExp, expScore); } 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(), doLogTransform); +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 gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; struct gtexGeneBed *geneBed = geneInfo->geneBed; -boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, - GTEX_LOG_TRANSFORM_DEFAULT); // Color in dense mode using transcriptClass Color statusColor = getTranscriptStatusColor(hvg, geneBed); if (vis != tvFull && vis != tvPack) { bedDrawSimpleAt(tg, geneBed, hvg, xOff, y, scale, font, statusColor, vis); return; } int heightPer = tg->heightPer; int graphX = gtexGraphX(geneBed); if (graphX < 0) return; -int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE); +int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); int yZero = topGraphHeight + y - 1; // yZero is bottom of graph #ifndef MULTI_REGION int x1 = xOff + graphX; // x1 is at left of graph int keepX = x1; // FIXME: Too many X's! drawGraphBase(hvg, keepX, yZero+1, geneInfo); int startX = x1; struct rgbColor lineColor = {.r=0}; int lineColorIx = hvGfxFindColorIx(hvg, lineColor.r, lineColor.g, lineColor.b); int barWidth = gtexBarWidth(); int graphPadding = gtexGraphPadding(); char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS, GTEX_COLORS_DEFAULT); @@ -523,37 +524,37 @@ double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; int i; int expCount = geneBed->expCount; struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; for (i=0; icolors[i]; if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX)) { // brighten colors a bit so they'll be more visible at this scale fillColor = gtexTissueBrightenColor(fillColor); } int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b); double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); int height = valToClippedHeight(expScore, maxMedian, viewMax, - gtexMaxGraphHeight(), doLogTransform); + gtexMaxGraphHeight(), extras->doLogTransform); if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX)) hvGfxBox(hvg, x1, yZero-height+1, barWidth, height, fillColorIx); else hvGfxOutlinedBox(hvg, x1, yZero-height+1, barWidth, height, fillColorIx, lineColorIx); // mark clipped bar with magenta tip - if (!doLogTransform && expScore > viewMax) + if (!extras->doLogTransform && expScore > viewMax) hvGfxBox(hvg, x1, yZero-height+1, barWidth, 1, clipColor); x1 = x1 + barWidth + graphPadding; } #endif // draw gene model int yGene = yZero + gtexGeneMargin() - 1; tg->heightPer = gtexGeneModelHeight() + 1; struct linkedFeatures *lf = linkedFeaturesFromGenePred(tg, geneInfo->geneModel, FALSE); lf->filterColor = statusColor; linkedFeaturesDrawAt(tg, lf, hvg, xOff, yGene, scale, font, color, tvSquish); tg->heightPer = heightPer; if (!geneInfo->medians2) return; @@ -565,36 +566,36 @@ drawGraphBase(hvg, keepX, yZero-1, geneInfo); for (i=0; icolors[i]; if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX)) { // brighten colors a bit so they'll be more visible at this scale struct hslColor hsl = mgRgbToHsl(fillColor); hsl.s = min(1000, hsl.s + 300); fillColor = mgHslToRgb(hsl); } int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b); double expScore = geneInfo->medians2[i]; int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexMaxGraphHeight(), - doLogTransform); + 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); - if (!doLogTransform && expScore > viewMax) + if (!extras->doLogTransform && expScore > viewMax) hvGfxBox(hvg, x1, yZero + height, barWidth, 1, clipColor); x1 = x1 + barWidth + graphPadding; } #endif } #ifdef MULTI_REGION static int gtexGeneNonPropPixelWidth(struct track *tg, void *item) /* Return end chromosome coordinate of item, including graph */ { struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; int graphWidth = gtexGraphWidth(geneInfo); return graphWidth; } #endif @@ -648,31 +649,31 @@ hvGfxText(hvg, x1, yZero + gtexGeneModelHeight() + gtexGeneMargin(), labelColor, font, "M"); startX = startX + tl.mWidth + 2; x1 = startX; } for (i=0; icolors[i]; if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX)) { // brighten colors a bit so they'll be more visible at this scale fillColor = gtexTissueBrightenColor(fillColor); } int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b); double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); - int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), doLogTransform); + int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), extras->doLogTransform); if (graphPadding == 0 || sameString(colorScheme, GTEX_COLORS_GTEX)) hvGfxBox(hvg, x1, yZero-height, barWidth, height, fillColorIx); else hvGfxOutlinedBox(hvg, x1, yZero-height, barWidth, height, fillColorIx, lineColorIx); x1 = x1 + barWidth + graphPadding; } // mark gene extent int yGene = yZero + gtexGeneMargin() - 1; /* GALT NOT DONE HERE NOW // draw gene model tg->heightPer = gtexGeneModelHeight()+1; struct linkedFeatures *lf = linkedFeaturesFromGenePred(tg, geneInfo->geneModel, FALSE); lf->filterColor = statusColor; @@ -684,65 +685,63 @@ // draw comparison graph (upside down) x1 = startX; yZero = yGene + gtexGeneModelHeight(); // yZero is at top of graph for (i=0; icolors[i]; if (barWidth == 1 && sameString(colorScheme, GTEX_COLORS_GTEX)) { // brighten colors a bit so they'll be more visible at this scale struct hslColor hsl = mgRgbToHsl(fillColor); hsl.s = min(1000, hsl.s + 300); fillColor = mgHslToRgb(hsl); } int fillColorIx = hvGfxFindColorIx(hvg, fillColor.r, fillColor.g, fillColor.b); double expScore = geneInfo->medians2[i]; - int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), doLogTransform); + int height = valToHeight(expScore, maxMedian, gtexMaxGraphHeight(), 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); x1 = x1 + barWidth + graphPadding; } } #endif static int gtexGeneItemHeightOptionalMax(struct track *tg, void *item, boolean isMax) { if (tg->visibility == tvSquish || tg->visibility == tvDense) return 0; if (isMax) { int extra = 0; if (((struct gtexGeneExtras *)tg->extraUiData)->isComparison) extra = gtexMaxGraphHeight() + 2; return gtexMaxGraphHeight() + gtexGeneMargin() + gtexGeneModelHeight() + extra; } if (item == NULL) return 0; struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; if (geneInfo->height != 0) return geneInfo->height; -boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, - GTEX_LOG_TRANSFORM_DEFAULT); -int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE); +int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); int bottomGraphHeight = 0; boolean isComparison = ((struct gtexGeneExtras *)tg->extraUiData)->isComparison; if (isComparison) { - bottomGraphHeight = max(gtexGeneGraphHeight(tg, geneInfo, doLogTransform, FALSE), + bottomGraphHeight = max(gtexGeneGraphHeight(tg, geneInfo, FALSE), tl.fontHeight) + gtexGeneMargin(); } int height = topGraphHeight + bottomGraphHeight + gtexGeneMargin() + gtexGeneModelHeight(); return height; } static int gtexGeneMaxHeight(struct track *tg) /* Maximum height in pixels of a gene graph */ { return gtexGeneItemHeightOptionalMax(tg, NULL, TRUE); } static int gtexGeneItemHeight(struct track *tg, void *item) { return gtexGeneItemHeightOptionalMax(tg, item, FALSE); @@ -782,88 +781,105 @@ static char *tissueExpressionText(struct gtexTissue *tissue, double expScore, boolean doLogTransform, char *qualifier) /* Construct mouseover text for tissue graph */ { 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 for each tissue (bar in the graph) or a single map for squish/dense modes */ +/* Create a map box on gene model and label, and one for each tissue (bar in the graph) in + * pack or ful modes. Just single map for squish/dense modes */ { if (tg->visibility == tvDense || tg->visibility == tvSquish) { genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height); return; } + +// add map boxes to gene model and label +struct gtexGeneInfo *geneInfo = item; struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +struct gtexGeneBed *geneBed = geneInfo->geneBed; +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 geneStart = max(geneInfo->geneModel->txStart, winStart); +int geneEnd = min(geneInfo->geneModel->txEnd, winEnd); +double scale = scaleForWindow(insideWidth, winStart, winEnd); +int x1 = round((double)((int)geneStart-winStart)*scale) + x; +int x2 = round((double)((int)geneEnd-winStart)*scale) + x; +int w = x2-x1; +char query[256]; +sqlSafef(query, sizeof(query), + "select kgXref.description from kgXref, knownToEnsembl where knownToEnsembl.value='%s' and knownToEnsembl.name=kgXref.kgID", geneBed->transcriptId); +struct sqlConnection *conn = hAllocConn(database); +char *desc = sqlQuickString(conn, query); +hFreeConn(&conn); +mapBoxHc(hvg, start, end, x, yGene, w, gtexGeneModelHeight()-1, tg->track, mapItemName, desc); + +// add maps to tissue bars in expresion graph struct gtexTissue *tissues = getTissues(); struct gtexTissue *tissue = NULL; -struct gtexGeneInfo *geneInfo = item; -struct gtexGeneBed *geneBed = geneInfo->geneBed; int barWidth = gtexBarWidth(); int padding = gtexGraphPadding(); double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; int graphX = gtexGraphX(geneBed); if (graphX < 0) return; + // x1 is at left of graph -int x1 = insideX + graphX; +x1 = insideX + graphX; if (geneInfo->medians2) { // skip over labels in comparison graphs x1 = x1 + tl.mWidth+ 2; } int i = 0; -boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, - GTEX_LOG_TRANSFORM_DEFAULT); -int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE); -topGraphHeight = max(topGraphHeight, tl.fontHeight); // label -int yZero = topGraphHeight + y - 1; // yZero is bottom of (top) graph - double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT); for (tissue = tissues; tissue != NULL; tissue = tissue->next, i++) { double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); int height = valToClippedHeight(expScore, maxMedian, viewMax, - gtexMaxGraphHeight(), doLogTransform); + gtexMaxGraphHeight(), extras->doLogTransform); char *qualifier = NULL; if (extras->isComparison && extras->isDifference) qualifier = "F-M"; mapBoxHc(hvg, start, end, x1, yZero-height, barWidth, height, tg->track, mapItemName, - tissueExpressionText(tissue, expScore, doLogTransform, qualifier)); + tissueExpressionText(tissue, expScore, extras->doLogTransform, qualifier)); // add map box to comparison graph if (geneInfo->medians2) { double expScore = geneInfo->medians2[i]; int height = valToClippedHeight(expScore, maxMedian, viewMax, - gtexMaxGraphHeight(), doLogTransform); + gtexMaxGraphHeight(), extras->doLogTransform); int y = yZero + gtexGeneModelHeight() + gtexGeneMargin(); // y is top of bottom graph if (extras->isComparison && extras->isDifference) qualifier = "M-F"; mapBoxHc(hvg, start, end, x1, y, barWidth, height, tg->track, mapItemName, - tissueExpressionText(tissue, expScore, doLogTransform, qualifier)); + tissueExpressionText(tissue, expScore, extras->doLogTransform, qualifier)); } x1 = x1 + barWidth + padding; } } static char *gtexGeneItemName(struct track *tg, void *item) /* Return gene name */ { struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; struct gtexGeneBed *geneBed = geneInfo->geneBed; return geneBed->name; } static int gtexGeneHeight(void *item) {