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");