3c079f1ab5ff66233574d8c5eff421698fe6b741
angie
  Mon Aug 18 11:51:58 2014 -0700
Revert "Checking in changes to make 'spectrum' (aka 'useScore') actually work on any pair of color/altColor settings.  It used to be that only shadesOfGray, shadesOfBrown and shadesOfSea worked, leaving most cases to be shadesOfGray.  I have sat on these changes for months.  I am also checking in ifdef'd out code to calc the shade on the fly, rather than relaying on track->colorShades set of precomputed 10 shades.  The only reason this code is not used is that it would require changing many many places/uses of colorShades.  Since I am bein laid off, it seems inappropriate to make this more dramatic change at this time."
This reverts commit a4adfa326bf8bec73020ee1a8aa0cb6251ea8663.

refs #13833

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 4186a98..eb07a8c 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -2414,32 +2414,32 @@
 		hvGfxFindColorIx(hvg, itemRgb.r, itemRgb.g, itemRgb.b);
 	}
     else
 	*retColor = *retBarbColor = lf->filterColor;
     }
 else if (tg->itemColor)
     {
     *retColor = tg->itemColor(tg, lf, hvg);
     *retBarbColor = tg->ixAltColor;
     }
 else if (tg->colorShades)
     {
     boolean isXeno = (tg->subType == lfSubXeno)
                                 || (tg->subType == lfSubChain)
                                 || startsWith("mrnaBla", tg->table);
-    *retColor     = colorBySpectrumOrDefault(hvg,tg,lf->grayIx+isXeno,*retColor);
-    *retBarbColor = colorBySpectrumOrDefault(hvg,tg,lf->grayIx,       *retBarbColor);
+    *retColor =  tg->colorShades[lf->grayIx+isXeno];
+    *retBarbColor =  tg->colorShades[lf->grayIx];
     }
 else
     {
     *retColor = tg->ixColor;
     *retBarbColor = tg->ixAltColor;
     }
 }
 
 Color linkedFeaturesNameColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Determine the color of the name for the linked feature. */
 {
 Color col, barbCol;
 lfColors(tg, item, hvg, &col, &barbCol);
 return col;
 }
@@ -5063,35 +5063,35 @@
 tg->drawItemAt  = gadDrawAt;
 tg->mapItem     = bedPlusLabelMapItem;
 tg->nextPrevExon = simpleBedNextPrevEdge;
 }
 
 void rgdQtlDrawAt(struct track *tg, void *item,
                   struct hvGfx *hvg, int xOff, int y,
                   double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a single rgdQtl item at position. */
 {
 struct bed *bed = item;
 struct trackDb *tdb = tg->tdb;
 
 if (tg->itemColor != NULL)
     color = tg->itemColor(tg, bed, hvg);
-else
+else if (tg->colorShades)
     {
     int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0"));
     int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000"));
-    color = colorBySpectrumOrDefault(hvg, tg, grayInRange(bed->score, scoreMin, scoreMax),color);
+    color = tg->colorShades[grayInRange(bed->score, scoreMin, scoreMax)];
     }
 if (color)
     {
     int heightPer = tg->heightPer;
     int s = max(bed->chromStart, winStart), e = min(bed->chromEnd, winEnd);
     if (s > e)
 	return;
     int x1 = round((s-winStart)*scale) + xOff;
     int x2 = round((e-winStart)*scale) + xOff;
     int w = x2 - x1;
     if (w < 1)
 	w = 1;
     hvGfxBox(hvg, x1, y, w, heightPer, color);
     if (tg->drawName && vis != tvSquish)
 	{
@@ -6179,31 +6179,34 @@
 //boolean thickDrawItem = (trackDbSetting(tdb, "thickDrawItem") != NULL);
 int colors[8] =
 {
 orangeColor,
 greenColor,
 blueColor,
 brickColor,
 darkBlueColor,
 darkGreenColor,
 1,
 MG_RED} ;
 
 if (tg->itemColor != NULL)
     color = tg->itemColor(tg, bed, hvg);
 else
-    color = colorBySpectrumOrDefault(hvg,tg,grayInRange(bed->score, scoreMin, scoreMax),color);
+    {
+    if (tg->colorShades)
+	color = tg->colorShades[grayInRange(bed->score, scoreMin, scoreMax)];
+    }
 
 w = x2-x1;
 if (w < 1)
     w = 1;
 //if (color)
     {
     int ii;
 
     for(ii=0; ii < 8; ii++)
 	{
 	if (bed->score & (1 << ii))
 	    hvGfxBox(hvg, x1, y+(ii*6), w, 6, colors[ii]);
 	}
     if (tg->drawName && vis != tvSquish)
 	{
@@ -7519,31 +7522,31 @@
 {
 return getSeqColorDefault(seqName, hvg, chromColor[0]);
 }
 
 Color lfChromColor(struct track *tg, void *item, struct hvGfx *hvg)
 /* Return color of chromosome for linked feature type items
  * where the chromosome is listed somewhere in the lf->name. */
 {
 struct linkedFeatures *lf = item;
 return getSeqColorDefault(lf->name, hvg, tg->ixColor);
 }
 
 Color interactionColor(struct track *tg, void *item, struct hvGfx *hvg)
 {
 struct linkedFeatures *lf = item;
-return colorBySpectrumOrDefault(hvg,tg,lf->grayIx,hvGfxFindRgb(hvg, &tg->color));
+return  tg->colorShades[lf->grayIx];
 
 #ifdef NOTNOW  // leaving this in the code in case we want chrom color again
 
 char *name = tg->itemName(tg, item);
 struct linkedFeatures *lf = item;
 if (slCount(lf->components) == 2)
     return MG_BLACK;
 return getSeqColorDefault(name, hvg, tg->ixColor);
 #endif
 }
 
 void interactionLeftLabels(struct track *tg, int seqStart, int seqEnd,
 	struct hvGfx *hvg, int xOff, int yOff, int width, int height,
 	boolean withCenterLabels, MgFont *font, Color color,
 	enum trackVisibility vis)
@@ -9172,125 +9175,30 @@
     if (!subtrack->limitedVisSet)
 	{
 	if (isSubtrackVisible(subtrack))
 	    subtrack->visibility = track->visibility;
 	else
 	    subtrack->visibility = tvHide;
 	}
 }
 
 boolean colorsSame(struct rgbColor *a, struct rgbColor *b)
 /* Return true if two colors are the same. */
 {
 return a->r == b->r && a->g == b->g && a->b == b->b;
 }
 
-//#define SPECTRUM_LIVE
-#ifdef SPECTRUM_LIVE
-// Define SPECTRUM_LIVE to enable live calculation of color rather than using track->colorShades
-// History: trackDb setting 'spectrum' (aka 'useScore') is defined to use an item's score to
-//          determine color on a spectrum.  This was originally limited to gray scale and only
-//          the discrete 10 shades defined in the colorShades array.  Two additional color scales
-//          were added (shadesOfBrown and shadesOfSea, but with no documentation on how a trackDb
-//          user could make use of these.  The array of shades has been widely used on track types
-//          beyond beds.
-// Spectrum support has been added to simply fill in the colorShades array on first use, based
-//          upon color/altColor.  This simple change does not need to touch on ubiquitous code that
-//          relies upon colorShades.  It is a targeted change with limited footprint, but maintains
-//          a hash of spectrums that gets built as needed.
-// Live spectrum, on the other hand would do away with colorShades and calculate the color whenever
-//          needed.  There would no longer be a limit to 10 shades, but would require extensive
-//          code changes to eliminate dependence upon the colorShades array.  There is no
-//          compelling efficiency of one method versus another.  Using live calculation should
-//          ultimately simplify code and structures.  But as I am being laid off, I feel it would
-//          be irresponsible to check in a larger change at this time
-// TODO: move to hvGfx.c
-Color hvGfxColorInSpectrum(struct hvGfx *hvg, struct rgbColor *colorOfZero,
-                           struct rgbColor *colorOfOne, float aboveZero)
-// Returns the color that lies between zero and one in the spectrum.
-{
-assert(aboveZero >= 0 && aboveZero <= 1.0);
-float belowOne = 1.0 - aboveZero;
-int red   = (belowOne * colorOfZero->r) + (aboveZero * colorOfOne->r);
-int green = (belowOne * colorOfZero->g) + (aboveZero * colorOfOne->g);
-int blue  = (belowOne * colorOfZero->b) + (aboveZero * colorOfOne->b);
-return hvGfxFindColorIx(hvg, red, green, blue);
-}
-
-Color colorWithinRange(struct hvGfx *hvg, struct rgbColor *bottomColor, struct rgbColor *topColor,
-                       int value, int rangeBottom, int rangeTop)
-// Returns color within range.  Colors outside of range will top or bottom out.
-// If range not defined, then range defaults to normal score range (0-1000).
-{
-// requested spectrum must have 2 colors
-if (!colorsSame(bottomColor, topColor))
-    {
-    if (rangeBottom >= rangeTop)
-        {
-        rangeBottom = 0;    // default this to normal score range
-        rangeTop    = 1000;
-        }
-    if (value < rangeBottom)
-        value = rangeBottom;
-    if (value > rangeTop)
-        value = rangeTop;
-    float aboveZero = ((float)value - rangeBottom)/(rangeTop - rangeBottom);
-    return hvGfxColorInSpectrum(hvg, bottomColor, topColor,aboveZero);
-    }
-else // no color range so use the only color
-    return hvGfxFindColorIx(hvg, topColor->r, topColor->g, topColor->b);
-}
-#endif//def SPECTRUM_LIVE
-
-Color colorBySpectrumOrDefault(struct hvGfx *hvg, struct track *track,int shade,Color defaultColor)
-// Returns color to use if spectrum exists, else returns default
-{
-if (track->tdb->useScore && track->colorShades == NULL)
-    {
-#ifdef SPECTRUM_LIVE
-    return colorWithinTrackIxRange(hvg,track,shade);
-#else// ifndef SPECTRUM_LIVE
-    struct rgbColor paintItBlack = {0, 0, 0};
-    if (!colorsSame(&paintItBlack, &track->color)
-    ||  !colorsSame(&paintItBlack, &track->altColor))
-        {
-        // Caching of the spectrum may be overkill, but if there are hundreds, this will be helpful
-        // An slPair list would be more space efficient, but with slower lookups
-        static struct hash *spectrumHash = NULL;
-        char spectrumName[32];
-        safef(spectrumName,32,"%02X%02X%02X,%02X%02X%02X",
-                             track->color.r,   track->color.g,   track->color.b,
-                          track->altColor.r,track->altColor.g,track->altColor.b);
-        if (spectrumHash == NULL)
-            spectrumHash = hashNew(4); // small hash
-        else
-            track->colorShades = hashFindVal(spectrumHash,spectrumName);
-        if (track->colorShades == NULL)
-            {
-            track->colorShades = needMem(sizeof(Color *) * maxShade + 2);
-            hvGfxMakeColorGradient(hvg, &track->color, &track->altColor,
-                                   maxShade+1, track->colorShades);
-            hashAddUnique(spectrumHash,spectrumName,track->colorShades);
-            }
-        }
-#endif//ndef SPECTRUM_LIVE
-    }
-if (track->colorShades == NULL || shade > maxShade + 1) // true range is 1 to 10.
-    return defaultColor;
-return track->colorShades[shade];
-}
-
 #ifndef GBROWSE
 void loadValAl(struct track *tg)
 /* Load the items in one custom track - just move beds in
  * window... */
 {
 struct linkedFeatures *lfList = NULL, *lf;
 struct bed *bed, *list = NULL;
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr;
 char **row;
 int rowOffset;
 
 sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset);
 while ((row = sqlNextRow(sr)) != NULL)
     {
@@ -9933,31 +9841,34 @@
                            MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a right- or left-pointing triangle at position.
  * If item has width > 1 or block/cds structure, those will be ignored --
  * this only draws a triangle (direction depending on strand). */
 {
 struct bed *bed = item;
 int x1 = round((double)((int)bed->chromStart-winStart)*scale) + xOff;
 int y2 = y + tg->heightPer-1;
 struct trackDb *tdb = tg->tdb;
 int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0"));
 int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000"));
 
 if (tg->itemColor != NULL)
     color = tg->itemColor(tg, bed, hvg);
 else
-    color = colorBySpectrumOrDefault(hvg,tg,grayInRange(bed->score, scoreMin, scoreMax),color);
+    {
+    if (tg->colorShades)
+	color = tg->colorShades[grayInRange(bed->score, scoreMin, scoreMax)];
+    }
 
 drawTri(hvg, x1, y, y2, color, bed->strand[0]);
 }
 
 void simpleBedTriangleMethods(struct track *tg)
 /* Load up simple bed features methods, but use triangleDrawAt. */
 {
 bedMethods(tg);
 tg->drawItemAt = triangleDrawAt;
 }
 
 void loadColoredExonBed(struct track *tg)
 /* Load the items into a linkedFeaturesSeries. */
 {
 struct sqlConnection *conn = hAllocConn(database);
@@ -12448,86 +12359,119 @@
     }
 track->height = height;
 return track->height;
 }
 
 int trackPriCmp(const void *va, const void *vb)
 /* Compare for sort based on priority */
 {
 const struct track *a = *((struct track **)va);
 const struct track *b = *((struct track **)vb);
 
 return (a->priority - b->priority);
 }
 
 void makeCompositeTrack(struct track *track, struct trackDb *tdb)
-// Construct track subtrack list from trackDb entry.
+/* Construct track subtrack list from trackDb entry.
+ * Sets up color gradient in subtracks if requested */
 {
+unsigned char finalR = track->color.r, finalG = track->color.g,
+                            finalB = track->color.b;
+unsigned char altR = track->altColor.r, altG = track->altColor.g,
+                            altB = track->altColor.b;
+unsigned char deltaR = 0, deltaG = 0, deltaB = 0;
+
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendantLeaves(tdb->subtracks);
 
 struct trackDb *subTdb;
 int subCount = slCount(tdbRefList);
+int altColors = subCount - 1;
 struct track *subtrack = NULL;
 TrackHandler handler;
 boolean smart = FALSE;
 
 /* ignore if no subtracks */
 if (!subCount)
     return;
 
 char *compositeTrack = trackDbLocalSetting(tdb, "compositeTrack");
 /* look out for tracks that manage their own subtracks */
 if (startsWith("wig", tdb->type) || startsWith("bedGraph", tdb->type) ||
     (compositeTrack != NULL && rStringIn("smart", compositeTrack)))
         smart = TRUE;
 
 /* setup function handlers for composite track */
 handler = lookupTrackHandlerClosestToHome(tdb);
 if (smart && handler != NULL)
     /* handles it's own load and height */
     handler(track);
 else
     {
     track->loadItems = compositeLoad;
     track->totalHeight = compositeTotalHeight;
     }
 
+if (altColors && (finalR || finalG || finalB))
+    {
+    /* not black -- make a color gradient for the subtracks,
+                from black, to the specified color */
+    deltaR = (finalR - altR) / altColors;
+    deltaG = (finalG - altG) / altColors;
+    deltaB = (finalB - altB) / altColors;
+    }
+
 /* fill in subtracks of composite track */
 for (tdbRef = tdbRefList; tdbRef != NULL; tdbRef = tdbRef->next)
     {
     subTdb = tdbRef->val;
 
     subtrack = trackFromTrackDb(subTdb);
     handler = lookupTrackHandlerClosestToHome(subTdb);
     if (handler != NULL)
         handler(subtrack);
 
     /* Add subtrack settings (table, colors, labels, vis & pri).  This is only
      * needed in the "not noInherit" case that hopefully will go away soon. */
     subtrack->track = subTdb->track;
     subtrack->table = subTdb->table;
     subtrack->shortLabel = subTdb->shortLabel;
     subtrack->longLabel = subTdb->longLabel;
     subtrack->priority = subTdb->priority;
     subtrack->parent = track;
 
+    /* Add color gradient. */
+    if (finalR || finalG || finalB)
+	{
+	subtrack->color.r = altR;
+	subtrack->altColor.r = (255+altR)/2;
+	altR += deltaR;
+	subtrack->color.g = altG;
+	subtrack->altColor.g = (255+altG)/2;
+	altG += deltaG;
+	subtrack->color.b = altB;
+	subtrack->altColor.b = (255+altB)/2;
+	altB += deltaB;
+	}
+    else
+	{
 	subtrack->color.r = subTdb->colorR;
 	subtrack->color.g = subTdb->colorG;
 	subtrack->color.b = subTdb->colorB;
 	subtrack->altColor.r = subTdb->altColorR;
 	subtrack->altColor.g = subTdb->altColorG;
 	subtrack->altColor.b = subTdb->altColorB;
+	}
     slAddHead(&track->subtracks, subtrack);
     }
 slSort(&track->subtracks, trackPriCmp);
 }
 
 struct track *trackFromTrackDb(struct trackDb *tdb)
 /* Create a track based on the tdb */
 {
 struct track *track = NULL;
 char *exonArrows;
 char *nextItem;
 
 if (!tdb)
     return NULL;
 track = trackNew();
@@ -12564,38 +12508,34 @@
 track->lineHeight = tl.fontHeight+1;
 track->heightPer = track->lineHeight - 1;
 track->private = tdb->private;
 track->defaultPriority = tdb->priority;
 char lookUpName[256];
 safef(lookUpName, sizeof(lookUpName), "%s.priority", tdb->track);
 tdb->priority = cartUsualDouble(cart, lookUpName, tdb->priority);
 track->priority = tdb->priority;
 track->groupName = cloneString(tdb->grp);
 /* save default priority and group so we can reset it later */
 track->defaultGroupName = cloneString(tdb->grp);
 track->canPack = tdb->canPack;
 if (tdb->useScore)
     {
     /* Todo: expand spectrum opportunities. */
-    struct rgbColor paintItBlack = {0, 0, 0};
     if (colorsSame(&brownColor, &track->color))
         track->colorShades = shadesOfBrown;
     else if (colorsSame(&darkSeaColor, &track->color))
         track->colorShades = shadesOfSea;
-    else if (!colorsSame(&paintItBlack, &track->color)
-         ||  !colorsSame(&paintItBlack, &track->altColor))
-        track->colorShades = NULL; // Signal to generate spectrum on first need
     else
 	track->colorShades = shadesOfGray;
     }
 track->tdb = tdb;
 
 /* Handle remote database settings - just a JK experiment at the moment. */
 track->remoteSqlHost = trackDbSetting(tdb, "sqlHost");
 track->remoteSqlUser = trackDbSetting(tdb, "sqlUser");
 track->remoteSqlPassword = trackDbSetting(tdb, "sqlPassword");
 track->remoteSqlDatabase = trackDbSetting(tdb, "sqlDatabase");
 track->remoteSqlTable = trackDbSetting(tdb, "sqlTable");
 track->isRemoteSql =  (track->remoteSqlHost != NULL && track->remoteSqlUser != NULL
 			&& track->remoteSqlDatabase != NULL && track->remoteSqlTable !=NULL);
 
 exonArrows = trackDbSetting(tdb, "exonArrows");