529fd44f904b874ea9b1a5bc80fe5dec3a5970a8
kate
  Wed Mar 23 15:16:33 2016 -0700
Add checkbox to limit to protein coding genes (I keep wanting this option during testing.). refs #15645

diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c
index 56c5e3a..caa71a4 100644
--- src/hg/hgTracks/gtexTracks.c
+++ src/hg/hgTracks/gtexTracks.c
@@ -6,30 +6,31 @@
 #include "common.h"
 #include "hgTracks.h"
 #include "hvGfx.h"
 #include "rainbow.h"
 #include "gtexInfo.h"
 #include "gtexGeneBed.h"
 #include "gtexTissue.h"
 #include "gtexTissueData.h"
 #include "gtexUi.h"
 #include "spaceSaver.h"
 
 struct gtexGeneExtras 
 /* Track info */
     {
     char *version;              /* Suffix to table name, e.g. 'V6' */
+    boolean codingOnly;       /* User filter to limit display to coding genes */
     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 gtexTissue *tissues; /* Cache tissue names, descriptions */
     struct hash *tissueFilter;  /* For filter. NULL out excluded tissues */
     };
 
 struct gtexGeneInfo
 /* GTEx gene model, names, and expression medians */
     {
     struct gtexGeneInfo *next;  /* Next in singly linked list */
@@ -83,73 +84,73 @@
 char *geneClass = gtexGeneClass(geneBed);
 if (geneClass == NULL)
     return statusColors.unknown;
 if (sameString(geneClass, "coding"))
     return statusColors.coding;
 if (sameString(geneClass, "nonCoding"))
     return statusColors.nonCoding;
 if (sameString(geneClass, "pseudo"))
     return statusColors.pseudo;
 return statusColors.unknown;
 }
 
 /***********************************************/
 /* Cache tissue info */
 
-struct gtexTissue *getTissues()
+struct gtexTissue *getTissues(char *version)
 /* Get and cache tissue metadata from database */
 {
 static struct gtexTissue *gtexTissues = NULL;
 
 if (!gtexTissues)
-    gtexTissues = gtexGetTissues();
+    gtexTissues = gtexGetTissues(version);
 return gtexTissues;
 }
 
-int getTissueCount()
+int getTissueCount(char *version)
 /* Get and cache the number of tissues in GTEx tissue table */
 {
 static int tissueCount = 0;
 
 if (!tissueCount)
-    tissueCount = slCount(getTissues());
+    tissueCount = slCount(getTissues(version));
 return tissueCount;
 }
 
-char *getTissueName(int id)
+char *getTissueName(int id, char *version)
 /* Get tissue name from id, cacheing */
 {
 static char **tissueNames = NULL;
 
 struct gtexTissue *tissue;
-int count = getTissueCount();
+int count = getTissueCount(version);
 if (!tissueNames)
     {
-    struct gtexTissue *tissues = getTissues();
+    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];
 }
 
-struct rgbColor *getGtexTissueColors()
+struct rgbColor *getGtexTissueColors(char *version)
 /* Get RGB colors from tissue table */
 {
-struct gtexTissue *tissues = getTissues();
+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++;
     }
 return colors;
 }
 
@@ -207,34 +208,34 @@
             hashAdd(scoreHash, tissue, score);
         }
     sqlFreeResult(&sr);
     hFreeConn(&conn);
 
     // get tissue medians for each sample subset
     double *medians1;
     double *medians2;
     AllocArray(medians1, expCount);
     AllocArray(medians2, expCount);
     int i;
     for (i=0; i<geneBed->expCount; i++)
         {
         //medians1[i] = -1, medians2[i] = -1;       // mark missing tissues ?
         struct slDouble *scores;
-        scores = hashFindVal(scoreHash1, getTissueName(i));
+        scores = hashFindVal(scoreHash1, getTissueName(i, extras->version));
         if (scores)
             medians1[i] = slDoubleMedian(scores);
-        scores = hashFindVal(scoreHash2, getTissueName(i));
+        scores = hashFindVal(scoreHash2, getTissueName(i, extras->version));
         if (scores)
             medians2[i] = slDoubleMedian(scores);
         }
     if (extras->isDifference)
         {
         for (i=0; i<geneBed->expCount; i++)
             {
             if (medians1[i] >= medians2[i])
                 {
                 medians1[i] -= medians2[i];
                 medians2[i] = 0;
                 }
             else
                 {
                 medians2[i] -= medians1[i];
@@ -242,31 +243,31 @@
                 }
             }
         }
     geneInfo->medians1 = medians1;
     geneInfo->medians2 = medians2;
     }
 }
 
 static int gtexGeneItemHeight(struct track *tg, void *item);
 
 static void filterTissues(struct track *tg)
 /* Check cart for tissue selection.  NULL out unselected tissues in tissue list */
 {
 struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
 struct gtexTissue *tis = NULL;
-extras->tissues = getTissues();
+extras->tissues = getTissues(extras->version);
 extras->tissueFilter = hashNew(0);
 if (cartListVarExistsAnyLevel(cart, tg->tdb, FALSE, GTEX_TISSUE_SELECT))
     {
     struct slName *selectedValues = cartOptionalSlNameListClosestToHome(cart, tg->tdb, 
                                                         FALSE, GTEX_TISSUE_SELECT);
     if (selectedValues != NULL)
         {
         struct slName *name;
         for (name = selectedValues; name != NULL; name = name->next)
             hashAdd(extras->tissueFilter, name->name, name->name);
         return;
         }
     }
 /* no filter */
 for (tis = extras->tissues; tis != NULL; tis = tis->next)
@@ -296,67 +297,74 @@
 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,
                         GTEX_COMPARISON_DEFAULT);
 extras->isDifference = sameString(comparison, GTEX_COMPARISON_DIFF) ? TRUE : FALSE;
 extras->maxMedian = gtexMaxMedianScore(extras->version);
-
+extras->codingOnly = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_CODING_GENE_FILTER,
+                                                        GTEX_CODING_GENE_FILTER_DEFAULT);
 /* Get geneModels in range */
 char buf[256];
 char *modelTable = "gtexGeneModel";
 safef(buf, sizeof(buf), "%s%s", modelTable, extras->version ? extras->version: "");
 struct hash *modelHash = loadGeneModels(buf);
 
 /* Get geneBeds (names and all-sample tissue median scores) in range */
 bedLoadItem(tg, tg->table, (ItemLoader)gtexGeneBedLoad);
 
 /* Create geneInfo items with BED and geneModels */
 struct gtexGeneInfo *geneInfo = NULL, *list = NULL;
 struct gtexGeneBed *geneBed = (struct gtexGeneBed *)tg->items;
 
 /* Load tissue colors: GTEx or rainbow */
 #ifdef COLOR_SCHEME
 char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS, 
                         GTEX_COLORS_DEFAULT);
 #else
 char *colorScheme = GTEX_COLORS_DEFAULT;
 #endif
 if (sameString(colorScheme, GTEX_COLORS_GTEX))
     {
-    extras->colors = getGtexTissueColors();
+    extras->colors = getGtexTissueColors(extras->version);
     }
 else
     {
     if (geneBed)
 	{
 	int expCount = geneBed->expCount;
 	extras->colors = getRainbow(&saturatedRainbowAtPos, expCount);
 	}
     }
 filterTissues(tg);
 
 while (geneBed != NULL)
     {
+    if (extras->codingOnly && !gtexGeneIsCoding(geneBed))
+        {
+        // apologies for messy short-circuit
+        geneBed = geneBed->next;
+        continue;
+        }
     AllocVar(geneInfo);
     geneInfo->geneBed = geneBed;
     geneInfo->geneModel = hashFindVal(modelHash, geneBed->geneId); // sometimes this is missing, hash returns NULL. do we check?
     // NOTE: Consider loading all gene descriptions to save queries
     char query[256];
     sqlSafef(query, sizeof(query),
             "select kgXref.description from kgXref where geneSymbol='%s'", geneBed->name);
     struct sqlConnection *conn = hAllocConn(database);
     char *desc = sqlQuickString(conn, query);
     hFreeConn(&conn);
     if (desc)
         {
         // hg38 known genes has extra detail about source; strip it
         char *fromDetail = strstrNoCase(desc, "(from");
         if (fromDetail)
@@ -510,31 +518,31 @@
 hvGfxBox(hvg, x, y, graphWidth, 1, lightGray);
 }
 
 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 (!filterTissue(tg, getTissueName(i)))
+    if (!filterTissue(tg, getTissueName(i, extras->version)))
         continue;
     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(), 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)
@@ -750,31 +758,31 @@
     {
     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;
 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();
+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);
 if (graphX < 0)
     return;
 
 // x1 is at left of graph
 x1 = insideX + graphX;
 
 if (geneInfo->medians2)
     {
     // skip over labels in comparison graphs