f4aba74550dea6d8548ba891cb9d057eaf6de43e
kate
  Wed Mar 22 12:30:24 2017 -0700
Fix bogus color cacheing.  Its now per-track

diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c
index 31a2434..d7e5a9e 100644
--- src/hg/hgTracks/gtexTracks.c
+++ src/hg/hgTracks/gtexTracks.c
@@ -36,31 +36,35 @@
 struct gtexGeneExtras 
 /* Track info */
     {
     char *version;              /* Suffix to table name, e.g. 'V6' */
     boolean codingOnly;         /* User filter to limit display to coding genes */
     boolean showExons;          /* Show gene model exons */
     boolean noWhiteout;         /* Suppress whiteout of graph background (allow highlight, blue lines) */
     enum geneLabelStyle labelStyle;  /* Show gene symbol, accession, or both */ 
     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 gtexTissue *tissues; /* Tissue names, descriptions */
+    int tissueCount;            /* Tissue count - derived from above */
+    char **tissueNames;         /* Tissue names by id - derived from above */
+    char **tissueLabels;        /* Tissue labels by id - derived from above */
+    char **tissueDescriptions;  /* Tissue descriptions by id - derived from above */
     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 */
     struct gtexGeneBed *geneBed;/* Gene name, id, type, exp count and medians 
                                         from BED table */
     struct genePred *geneModel; /* Gene structure from model table */
     char *label;                /* Name, accession, or both */
     char *description;          /* Gene description */
     double *medians1;            /* Computed medians */
     double *medians2;            /* Computed medians for comparison (inverse) graph */
     int height;                  /* Item height in pixels */
@@ -107,134 +111,136 @@
 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(char *version)
+struct gtexTissue *getTissues(struct track *tg, char *version)
 /* Get and cache tissue metadata from database */
 {
-static struct gtexTissue *gtexTissues = NULL;
-
-if (!gtexTissues)
-    gtexTissues = gtexGetTissues(version);
-return gtexTissues;
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
+if (!extras->tissues)
+    extras->tissues = gtexGetTissues(version);
+return extras->tissues;
 }
 
-int getTissueCount(char *version)
+int getTissueCount(struct track *tg, 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;
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
+if (!extras->tissueCount)
+    extras->tissueCount = slCount(getTissues(tg, version));
+return extras->tissueCount;
 }
 
-char *getTissueName(int id, char *version)
+char *getTissueName(struct track *tg, int id, char *version)
 /* Get tissue name from id, cacheing */
 {
-static char **tissueNames = NULL;
 struct gtexTissue *tissue;
-int count = getTissueCount(version);
-if (!tissueNames)
+int count = getTissueCount(tg, version);
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
+if (!extras->tissueNames)
     {
-    struct gtexTissue *tissues = getTissues(version);
-    AllocArray(tissueNames, count);
+    struct gtexTissue *tissues = getTissues(tg, version);
+    AllocArray(extras->tissueNames, count);
     for (tissue = tissues; tissue != NULL; tissue = tissue->next)
-        tissueNames[tissue->id] = cloneString(tissue->name);
+        extras->tissueNames[tissue->id] = cloneString(tissue->name);
     }
 if (id >= count)
     errAbort("GTEx tissue table problem: can't find id %d\n", id);
-return tissueNames[id];
+return extras->tissueNames[id];
 }
 
-char *getTissueDescription(int id, char *version)
+char *getTissueDescription(struct track *tg, int id, char *version)
 /* Get tissue description from id, cacheing */
 {
-static char **tissueDescriptions = NULL;
 struct gtexTissue *tissue;
-int count = getTissueCount(version);
-if (!tissueDescriptions)
+int count = getTissueCount(tg, version);
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
+if (!extras->tissueDescriptions)
     {
-    struct gtexTissue *tissues = getTissues(version);
-    AllocArray(tissueDescriptions, count);
+    struct gtexTissue *tissues = getTissues(tg, version);
+    AllocArray(extras->tissueDescriptions, count);
     for (tissue = tissues; tissue != NULL; tissue = tissue->next)
-        tissueDescriptions[tissue->id] = cloneString(tissue->description);
+        extras->tissueDescriptions[tissue->id] = cloneString(tissue->description);
     }
 if (id >= count)
     errAbort("GTEx tissue table problem: can't find id %d\n", id);
-return tissueDescriptions[id];
+return extras->tissueDescriptions[id];
 }
 
-struct rgbColor *getGtexTissueColors(char *version)
+struct rgbColor *getGtexTissueColors(struct track *tg, char *version)
 /* Get RGB colors from tissue table */
 {
-struct gtexTissue *tissues = getTissues(version);
+struct gtexTissue *tissues = getTissues(tg, version);
 struct gtexTissue *tissue = NULL;
-int count = slCount(tissues);
-struct rgbColor *colors;
-AllocArray(colors, count);
+int count = getTissueCount(tg, version);
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
+if (!extras->colors)
+    {
+    AllocArray(extras->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)};
+        extras->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;
+    }
+return extras->colors;
 }
 
 /*****************************************************************/
 /* Load sample data, gene info, and anything else needed to draw */
 
 static struct hash *loadGeneModels(char *table)
 /* Load gene models from table */
 {
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr;
 char **row;
 int rowOffset;
 sr = hRangeQuery(conn, table, chromName, winStart, winEnd, NULL, &rowOffset);
 
 struct hash *modelHash = newHash(0);
 struct genePred *model = NULL;
 while ((row = sqlNextRow(sr)) != NULL)
     {
     model = genePredLoad(row+rowOffset);
     hashAdd(modelHash, model->name, model);
     }
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 return modelHash;
 }
 
-static void loadComputedMedians(struct gtexGeneInfo *geneInfo, struct gtexGeneExtras *extras)
+static void loadComputedMedians(struct track *tg, struct gtexGeneInfo *geneInfo)
 /* Compute medians based on graph type.  Returns a list of 2 for comparison graph types */
 {
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 int expCount = geneBed->expCount;
+struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
 if (extras->isComparison)
     {
     // create two score hashes, one for each sample subset
     struct hash *scoreHash1 = hashNew(0), *scoreHash2 = hashNew(0);
     struct sqlConnection *conn = hAllocConn("hgFixed");
     char query[1024];
     char **row;
     sqlSafef(query, sizeof(query), "select gtexSampleData.sample, gtexDonor.gender, gtexSampleData.tissue, gtexSampleData.score from gtexSampleData, gtexSample, gtexDonor where gtexSampleData.geneId='%s' and gtexSampleData.sample=gtexSample.sampleId and gtexSample.donor=gtexDonor.name", geneBed->geneId);
     struct sqlResult *sr = sqlGetResult(conn, query);
     while ((row = sqlNextRow(sr)) != NULL)
         {
         char gender = *row[1];
         // TODO: generalize for other comparison graphs (this code just for M/F comparison)
         struct hash *scoreHash = ((gender == 'F') ? scoreHash1 : scoreHash2);
         char *tissue = cloneString(row[2]);
@@ -248,34 +254,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, extras->version));
+        scores = hashFindVal(scoreHash1, getTissueName(tg, i, extras->version));
         if (scores)
             medians1[i] = slDoubleMedian(scores);
-        scores = hashFindVal(scoreHash2, getTissueName(i, extras->version));
+        scores = hashFindVal(scoreHash2, getTissueName(tg, 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];
@@ -309,31 +315,31 @@
 if (winSize < WIN_MAX_GRAPH)
     return MAX_GENE_BOX_HEIGHT;
 else if (winSize < WIN_MED_GRAPH)
     return MED_GENE_BOX_HEIGHT;
 else
     return MIN_GENE_BOX_HEIGHT;
 }
 
 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->version);
+extras->tissues = getTissues(tg, 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)
@@ -432,33 +438,34 @@
 /* Get geneBeds (names and all-sample tissue median scores) in range */
 char *filter = getScoreFilterClause(cart, tg->tdb, NULL);
 bedLoadItemWhere(tg, tg->table, filter, (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->version);
+    extras->colors = getGtexTissueColors(tg, extras->version);
     }
 else
     {
     if (geneBed)
 	{
 	int expCount = geneBed->expCount;
 	extras->colors = getRainbow(&saturatedRainbowAtPos, expCount);
 	}
     }
 filterTissues(tg);
 
 while (geneBed != NULL)
     {
     if (extras->codingOnly && !gtexGeneIsCoding(geneBed))
         {
@@ -503,31 +510,31 @@
         // also strip 'homo sapiens' prefix
         #define SPECIES_PREFIX  "Homo sapiens "
         if (startsWith(SPECIES_PREFIX, desc))
             desc += strlen(SPECIES_PREFIX);
         geneInfo->description = desc;
         }
     else
         geneInfo->description = geneInfo->geneBed->name;
 
     slAddHead(&list, geneInfo);
     geneBed = geneBed->next;
     geneInfo->geneBed->next = NULL;
 
     if (extras->isComparison && (tg->visibility == tvFull || tg->visibility == tvPack))
         // compute medians based on configuration (comparisons, and later, filters)
-        loadComputedMedians(geneInfo, extras);
+        loadComputedMedians(tg, geneInfo);
     geneInfo->height = gtexGeneItemHeight(tg, geneInfo);
 
     }
 slReverse(&list);
 tg->items = list;
 }
 
 /***********************************************/
 /* Draw */
 
 /* Bargraph layouts for three window sizes */
 #define WIN_MAX_GRAPH 50000
 #define MAX_GRAPH_HEIGHT 175
 #define MAX_BAR_WIDTH 5
 #define MAX_GRAPH_PADDING 2
@@ -651,31 +658,31 @@
 return valToHeight(useVal, useMax, gtexMaxGraphHeight(), doLogTransform);
 }
 
 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, extras->version)))
+    if (!filterTissue(tg, getTissueName(tg, 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 drawGraphBox(struct track *tg, struct gtexGeneInfo *geneInfo, struct hvGfx *hvg, int x, int y)
 /* Draw white background for graph */
@@ -962,48 +969,48 @@
 if (tg->limitedVis == tvDense)
     {
     genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height);
     return;
     }
 struct gtexGeneInfo *geneInfo = item;
 struct gtexGeneBed *geneBed = geneInfo->geneBed;
 struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData;
 int geneStart = geneBed->chromStart;
 int geneEnd = geneBed->chromEnd;
 if (tg->limitedVis == tvSquish)
     {
     int tisId = maxTissueForGene(geneBed);
     char *maxTissue = "";
     if (tisId > 1)
-        maxTissue = getTissueDescription(tisId, extras->version);
+        maxTissue = getTissueDescription(tg, tisId, extras->version);
     char buf[128];
     safef(buf, sizeof buf, "%s %s", geneBed->name, maxTissue);
     int x1, x2;
     getItemX(geneStart, geneEnd, &x1, &x2);
     int width = max(1, x2-x1);
     mapBoxHc(hvg, geneStart, geneEnd, x1, 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 x1 = insideX;
 
 
 // add maps to tissue bars in expresion graph
-struct gtexTissue *tissues = getTissues(extras->version);
+struct gtexTissue *tissues = getTissues(tg, 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