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; i<expCount; i++)
     {
     if (doTop)
         expScore = (geneInfo->medians1 ? 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; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[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; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[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; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[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; i<expCount; i++)
     {
     struct rgbColor fillColor = extras->colors[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)
 {