ea98af2e746d154a9a3d493a5b2d9f5932b39d47
kate
  Sun May 5 15:23:59 2019 -0700
Clean up UI for factorSource right labels, and make both selections default on (checking w/ JK). Enhancements for ENCODE TF Clusters track update. refs #21139

diff --git src/hg/hgTracks/factorSource.c src/hg/hgTracks/factorSource.c
index 223277a..e130aa2 100644
--- src/hg/hgTracks/factorSource.c
+++ src/hg/hgTracks/factorSource.c
@@ -1,372 +1,372 @@
 /* Deal with factorSource type tracks, which are used to display 
  * transcription factor binding sites as measured in a number of
  * tissue or cell type sources. */
 
 /* Copyright (C) 2014 The Regents of the University of California 
  * See README in this or parent directory for licensing information. */
 
 #include "common.h"
 #include "hash.h"
 #include "linefile.h"
 #include "jksql.h"
 #include "hdb.h"
 #include "hgTracks.h"
 #include "expRecord.h"
 #include "dystring.h"
 #include "factorSource.h"
 #include "bed6FloatScore.h"
 
 static struct factorSource *loadOne(char **row)
 /* Load up factorSource from array of strings. */
 {
 return factorSourceLoad(row);
 }
 
 /* Save info about factors and their motifs */
 struct factorSourceInfo {
     boolean showCellAbbrevs;
     boolean showExpCounts;
     struct hash *factorExpCounts;
     struct hash *factorChoices;
     struct hash *motifTargets;
     struct bed6FloatScore *motifs;
 };
 
 boolean factorFilter(struct track *track, void *item)
 /* Returns true if an item should be passed by the filter. NOTE: single filter supported here*/
 {
 struct hash *factorHash = ((struct factorSourceInfo *)track->extraUiData)->factorChoices;
 if (track->extraUiData != NULL && factorHash != NULL)
     if (hashLookup(factorHash, ((struct factorSource *)item)->name) != NULL)
         return TRUE;
 return FALSE;
 }
 
 static void factorSourceLoadItems(struct track *track)
 /* Load all items (and motifs if table is present) in window */
 {
 bedLoadItem(track, track->table, (ItemLoader)loadOne);
 if (track->items == NULL)
     return;
 
 struct factorSourceInfo *fsInfo = NULL;
 AllocVar(fsInfo);
 track->extraUiData = fsInfo;
 
 // Check UI setting to show cell abbreviations or counts
 char varName[64];
 safef(varName, sizeof(varName), "%s.showCellAbbrevs", track->track);
 fsInfo->showCellAbbrevs = cartUsualBoolean(cart, varName, TRUE);
 safef(varName, sizeof(varName), "%s.showExpCounts", track->track);
-fsInfo->showExpCounts = cartUsualBoolean(cart, varName, FALSE);
+fsInfo->showExpCounts = cartUsualBoolean(cart, varName, TRUE);
 
 if (fsInfo->showExpCounts)
     {
     struct sqlConnection *conn = hAllocConn(database);
     char query[256];
     char *inputTrackTable = trackDbRequiredSetting(track->tdb, "inputTrackTable");
     sqlSafef(query, sizeof(query), 
                 "select factor, count(*) as num from %s group by factor", inputTrackTable);
     fsInfo->factorExpCounts = sqlQuickHash(conn, query);
     // TODO: If we're worried about performance, can remake as hash of ints
     hFreeConn(&conn);
     }
 
 // Filter factors based on multi-select
 filterBy_t *filter = filterBySetGet(track->tdb, cart, NULL);
 if (filter != NULL && filter->slChoices != NULL && differentString(filter->slChoices->name, "All"))
     {
     struct slName *choice;
     struct hash *factorHash = newHash(0);
     for (choice = filter->slChoices; choice != NULL; choice = choice->next)
         {
         hashAdd(factorHash, choice->name, NULL);
         }
     fsInfo->factorChoices = factorHash;
     filterItems(track, factorFilter, "include");
 }
 
 // Motifs
 safef(varName, sizeof(varName), "%s.highlightMotifs", track->track);
 if (!cartUsualBoolean(cart, varName, trackDbSettingClosestToHomeOn(track->tdb, "motifDrawDefault")))
     return;
 
 char *motifMaxWindow = trackDbSetting(track->tdb, "motifMaxWindow");
 if (motifMaxWindow != NULL)
     if (winEnd - winStart > sqlUnsigned(motifMaxWindow))
         return;
 
 char *motifTable = trackDbSetting(track->tdb, "motifTable");
 if (motifTable == NULL)
     return;
 
 struct sqlConnection *conn = hAllocConn(database);
 if ((track->items != NULL) & sqlTableExists(conn, motifTable))
     {
 
     // Load all motifs for items in window (including motifs outside of window)
     struct slList *items = track->items;
     int winStartSave = winStart;
     int winEndSave = winEnd;
 
     winStart = min(winStart, ((struct factorSource *)items)->chromStart);
     winEnd = max(winEnd, ((struct factorSource *)items)->chromEnd);
     bedLoadItem(track, motifTable, (ItemLoader)bed6FloatScoreLoad);
     fsInfo->motifs = track->items;
 
     track->items = items;
     winStart = winStartSave;
     winEnd = winEndSave;
 
     char *motifMapTable = trackDbSetting(track->tdb, "motifMapTable");
     if (motifMapTable != NULL && sqlTableExists(conn, motifMapTable))
         {
         // Load map table 
         char query[256];
         struct sqlResult *sr = NULL;
         char **row = NULL;
         sqlSafef(query, sizeof(query), "select target, motif from %s", motifMapTable);
         sr = sqlGetResult(conn, query);
         struct hash *targetHash = newHash(0);
         while ((row = sqlNextRow(sr)) != NULL)
             {
             char *target = row[0];
             char *motifs = row[1];   // string, comma-sep list, or empty string
             if (motifs[0] != 0)
                 hashAdd(targetHash, target, slNameListFromString(motifs, ','));
             }
         sqlFreeResult(&sr);
         fsInfo->motifTargets = targetHash;
         }
     }
 hFreeConn(&conn);
 }
 
 static int factorSourceRightPixels(struct track *track, void *item)
 /* Return number of pixels we need to the right. */
 {
 struct factorSourceInfo *fsInfo = (struct factorSourceInfo *)track->extraUiData;
 
 // can we test this here ?
 #ifdef BETTER_LAYOUT
 if (!(vis == tvFull || vis == tvPack))
     return 0;
 #endif
 struct factorSource *fs = item;
 struct dyString *dy = dyStringNew(0);
 if (fsInfo->showExpCounts)
     {
     dyStringPrintf(dy, "%d", fs->expCount);
     char *s = hashFindVal(fsInfo->factorExpCounts, fs->name);
     int allCount = s ? sqlUnsigned(s) : 0;
     if (fs->expCount != allCount)
         dyStringPrintf(dy, "/%d", allCount);
     if (fsInfo->showCellAbbrevs)
         dyStringAppend(dy, " ");
     }
 
 if (fsInfo->showCellAbbrevs)
     {
     int i;
     for (i=0; i<fs->expCount; ++i)
         {
         int expNum = fs->expNums[i];
         char *label = track->sources[expNum]->name;
         dyStringAppend(dy, label);
         }
     }
 int result = mgFontStringWidth(tl.font, dy->string);
 dyStringFree(&dy);
 return result;
 }
 
 static void factorSourceDrawItemAt(struct track *track, void *item, 
 	struct hvGfx *hvg, int xOff, int y, 
 	double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw factorSource item at a particular position. */
 {
 /* Figure out maximum score and draw box based on it. */
 struct factorSource *fs = item;
 int grayIx = grayInRange(fs->score, 0, 1000);
 color = shadesOfGray[grayIx];
 
 /* Calculate position, and draw box around where we are. */
 int heightPer = track->heightPer;
 int x1 = round((double)((int)fs->chromStart-winStart)*scale) + xOff;
 int x2 = round((double)((int)fs->chromEnd-winStart)*scale) + xOff;
 int w = x2-x1;
 if (w < 1)
     w = 1;
 hvGfxBox(hvg, x1, y, w, heightPer, color);
 if (vis != tvFull && vis != tvPack)
     return;
 
 /* Draw text to the right */
 int x = x2 + tl.mWidth/2;
 struct factorSourceInfo *fsInfo = (struct factorSourceInfo *)track->extraUiData;
 if (fsInfo->showExpCounts)
     {
     struct dyString *ds = dyStringNew(0);
     dyStringPrintf(ds, "%d", fs->expCount);
     char *s = hashFindVal(fsInfo->factorExpCounts, fs->name);
     int allCount = s ? sqlUnsigned(s) : 0;
     if (fs->expCount != allCount)
         dyStringPrintf(ds, "/%d", allCount);
     if (fsInfo->showCellAbbrevs)
         dyStringAppend(ds, " ");
     char *label = dyStringCannibalize(&ds);
     int w = mgFontStringWidth(font, label);
     hvGfxTextCentered(hvg, x, y, w, heightPer, MG_BLACK, font, label);
     x += w;
     }
 if (fsInfo->showCellAbbrevs)
     {
     int i;
     for (i=0; i<fs->expCount; ++i)
         {
         int id = fs->expNums[i];
         char *label = track->sources[id]->name;
         int w = mgFontStringWidth(font, label);
         float score = fs->expScores[i];
         int grayIx = grayInRange(score, 0, 1000);
         int color = shadesOfGray[grayIx];
         hvGfxTextCentered(hvg, x, y, w, heightPer, color, font, label);
         x += w;
         }
     }
 }
 
 static void factorSourceDrawMotifForItemAt(struct track *track, void *item, 
 	struct hvGfx *hvg, int xOff, int y, 
 	double scale, MgFont *font, Color color, enum trackVisibility vis)
 /* Draw motif on factorSource item at a particular position. */
 {
 struct factorSourceInfo *fsInfo = (struct factorSourceInfo *)track->extraUiData;
 if (fsInfo == NULL)
     return;
 
 // Draw region with highest motif score
 // NOTE: shows only canonical motif for the factor, so hides co-binding potential
 // NOTE: current table has single motif per factor
 struct factorSource *fs = item;
 int heightPer = track->heightPer;
 struct hash *targetHash = fsInfo->motifTargets;
 struct slName *motifNames = NULL;
 if (targetHash != NULL)
     motifNames = hashFindVal(targetHash, fs->name);
 if (motifNames == NULL)
     motifNames = slNameNew(fs->name);
 
 // Find motifs that lie completely within peak (sensible for ChIP-seq data ?)
 struct bed6FloatScore *m, *motif = NULL, *motifs = NULL;
 
 for (m = fsInfo->motifs; m != NULL && m->chromEnd <= fs->chromEnd; m = m->next)
     {
     if (m->chromStart < fs->chromStart)
         continue;
     if (!slNameInList(motifNames, m->name))
         continue;
     AllocVar(motif);
     motif->chrom = cloneString(m->chrom);
     motif->chromStart = m->chromStart;
     motif->chromEnd = m->chromEnd;
     motif->name = m->name;
     motif->score = m->score;
     motif->strand[0] = m->strand[0];
     slAddHead(&motifs, motif);
     }
 if (motifs == NULL)
     return;
 slSort(&motifs, bedCmpScore);
 slReverse(&motifs);
 
 #define HIGHEST_SCORING
 #ifdef HIGHEST_SCORING
 if ((motif = motifs) != NULL)
     {
     if (motif->chromStart > winEnd || motif->chromEnd < winStart)
         return;
 #else
 for (motif = motifs; motifs != NULL; motif = motif->next)
     {
     // exclude motifs outside of window
     if (motif->chromStart > winEnd || motif->chromEnd < winStart)
         continue;
 #endif
     int x1 = round((double)((int)motif->chromStart-winStart)*scale) + xOff;
     int x2 = round((double)((int)motif->chromEnd-winStart)*scale) + xOff;
     int w = x2-x1;
     if (w < 1)
         w = 1;
     hvGfxBox(hvg, x1, y, w, heightPer, color);
     if (w > 2)
         {
         // Draw chevrons for directionality
         Color textColor = hvGfxContrastingColor(hvg, color);
         int midY = y + (heightPer>>1);
         int dir = (*motif->strand == '+' ? 1 : -1);
         if (vis != tvDense)
             clippedBarbs(hvg, x1, midY, w, tl.barbHeight, tl.barbSpacing,
                        dir, textColor, TRUE);
         }
     }
 //bed6FloatScoreFreeList(&motifs);  # not worth exec time (or debug time)
 }
 
 static void factorSourceDraw(struct track *track, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width,
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw factorSource items. */
 {
 if (vis == tvDense)
     slSort(&track->items, bedCmpScore);
 genericDrawItems(track, seqStart, seqEnd, hvg, xOff, yOff, width,
 	font, color, vis);
 
 // Highlight motif regions in green
 color = hvGfxFindColorIx(hvg, 22, 182, 33);
 //Color color = hvGfxFindColorIx(hvg, 25, 204, 37);
 track->drawItemAt = factorSourceDrawMotifForItemAt;
 
 // suppress re-draw of item labels in motif color
 extern boolean withLeftLabels;
 boolean saveWithLeftLabels = withLeftLabels;
 withLeftLabels = FALSE;
 genericDrawItems(track, seqStart, seqEnd, hvg, xOff, yOff, width,
 	font, color, vis);
 withLeftLabels = saveWithLeftLabels;
 }
 
 void factorSourceMethods(struct track *track)
 /* Set up special methods for factorSource type tracks. */
 {
 /* Start out as a bed, and then specialize loader, mark self as packable. */
 track->bedSize = 5;
 bedMethods(track);
 track->drawItemAt = factorSourceDrawItemAt;
 track->drawItems = factorSourceDraw;
 track->loadItems = factorSourceLoadItems;
 track->itemRightPixels = factorSourceRightPixels;
 
 /* Get the associated data describing the various sources. */
 track->expTable = trackDbRequiredSetting(track->tdb, SOURCE_TABLE);
 struct sqlConnection *conn = hAllocConn(database);
 char query[256];
 track->sourceCount = sqlTableSizeIfExists(conn, track->expTable);
 sqlSafef(query, sizeof(query), "select * from %s order by id", track->expTable);
 struct expRecord *exp, *expList = expRecordLoadByQuery(conn, query);
 int expIx;
 AllocArray(track->sources, track->sourceCount);
 for (exp=expList, expIx=0; exp != NULL; exp = exp->next, expIx += 1)
     track->sources[expIx] = exp;
 hFreeConn(&conn);
 
 /* Figure out how many pixels need to the right. */
 #ifdef UNUSED
 int rightCount = tl.mWidth/2;
 for (expIx=0; expIx < track->sourceCount; ++expIx)
     rightCount += mgFontStringWidth(tl.font, track->sources[expIx]->name);
 track->sourceRightPixels = rightCount;
 #endif
 }