638114376e8f1e12d06674874170e83d5bef0b94
markd
  Mon Oct 27 20:19:42 2014 -0700
Added support for gencode filter by tag and highlight by tag and annotation method.  Currently only enabled in GENCODE V21.
diff --git src/hg/hgTracks/gencodeTracks.c src/hg/hgTracks/gencodeTracks.c
index d0f7805..8d0c9c3 100644
--- src/hg/hgTracks/gencodeTracks.c
+++ src/hg/hgTracks/gencodeTracks.c
@@ -11,63 +11,69 @@
 #include "genePred.h"
 
 struct gencodeQuery
 /* structure used to store information about the query being assembled.
  * this allows a join to bring in additional data without having to
  * do repeated queries. */
 {
     struct dyString *fields;                // select fields
     struct dyString *from;                  // from clause
     struct dyString *where;                 // where clause
     boolean isGenePredX;                    // does this have the extended fields?
     int nextFieldCol;                       // next available column in result row
     int supportLevelCol;                    // support level column if joined for highlighting, or -1 
     int transcriptTypeCol;                  // transcript type column if joined for highlighting, or -1 
     int transcriptSourceCol;                // transcript source column if joined for method highlighting, or -1 
+    int tagCol;                             // tag column if joined for method highlighting, or -1 
     filterBy_t *supportLevelHighlight;      // choices for support level highlighting if not NULL
     filterBy_t *transcriptTypeHighlight;    // choices for transcript type highlighting if not NULL
     filterBy_t *transcriptMethodHighlight;  // choices for transcript method highlighting if not NULL
+    filterBy_t *tagHighlight;               // choices for tag highlighting if not NULL
     boolean joinAttrs;                      // join the wgEncodeGencodeAttrs table
-    boolean joinTransSrc;                   // join the wgEncodeGencodeTranscriptSource table
     boolean joinSupportLevel;               // join the wgEncodeGencodeTranscriptionSupportLevel table
     boolean joinTranscriptSource;           // join the wgEncodeGencodeTranscriptSource table
+    boolean joinTag;                        // join the wgEncodeGencodeTag table
 };
 
 static struct gencodeQuery *gencodeQueryNew(void)
 /* construct a new gencodeQuery object */
 {
 struct gencodeQuery *gencodeQuery;
 AllocVar(gencodeQuery);
 gencodeQuery->fields = dyStringNew(0);
 gencodeQuery->from = dyStringNew(0);
 gencodeQuery->where = dyStringNew(0);
 gencodeQuery->supportLevelCol = -1;
 gencodeQuery->transcriptTypeCol = -1;
+gencodeQuery->transcriptSourceCol = -1;
+gencodeQuery->tagCol = -1;
 return gencodeQuery;
 }
 
 static void gencodeQueryFree(struct gencodeQuery **gencodeQueryPtr)
 /* construct a new gencodeQuery object */
 {
 struct gencodeQuery *gencodeQuery = *gencodeQueryPtr;
 if (gencodeQuery != NULL)
     {
     dyStringFree(&gencodeQuery->fields);
     dyStringFree(&gencodeQuery->from);
     dyStringFree(&gencodeQuery->where);
     filterBySetFree(&gencodeQuery->supportLevelHighlight);
     filterBySetFree(&gencodeQuery->transcriptTypeHighlight);
+    filterBySetFree(&gencodeQuery->transcriptMethodHighlight);
+    filterBySetFree(&gencodeQuery->tagHighlight);
     freeMem(gencodeQuery);
     *gencodeQueryPtr = NULL;
     }
 }
 
 static void gencodeQueryBeginSubWhere(struct gencodeQuery *gencodeQuery)
 /* begin adding new where sub-clause */
 {
 if (dyStringLen(gencodeQuery->where) > 0)
     dyStringAppend(gencodeQuery->where, " and ");
 dyStringAppend(gencodeQuery->where, "(");
 }
 
 static void gencodeQueryEndSubWhere(struct gencodeQuery *gencodeQuery)
 /* finish adding new where sub-clause */
@@ -129,31 +135,31 @@
 {
 struct slName *choice = NULL;
 for (choice = filterBy->slChoices; choice != NULL; choice = choice->next)
     {
     if (choice != filterBy->slChoices)
         dyStringAppend(gencodeQuery->where, " or ");
     filterByMethodChoiceQuery(choice->name, gencodeQuery);
     }
 }
 
 static void filterByMethodQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
 /* generate SQL where clause for annotation method filtering */
 {
 gencodeQueryBeginSubWhere(gencodeQuery);
 filterByMethodChoicesQuery(filterBy, gencodeQuery);
-gencodeQuery->joinTransSrc = TRUE;
+gencodeQuery->joinTranscriptSource = TRUE;
 gencodeQueryEndSubWhere(gencodeQuery);
 }
 
 static void filterBySupportLevelChoiceQuery(char *choice, struct gencodeQuery *gencodeQuery)
 /* add SQL expression GENCODE support choice. */
 {
 /* table is numeric (silly me), and string is tsl1..tsl5 or tslNA */
 dyStringPrintf(gencodeQuery->where, "(supLevel.level = %s)", tslSymToNumStr(choice));
 }
 
 static void filterBySupportLevelChoicesQuery(filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
 /* add support level compare clauses */
 {
 struct slName *choice = NULL;
 for (choice = filterBy->slChoices; choice != NULL; choice = choice->next)
@@ -161,53 +167,84 @@
     if (choice != filterBy->slChoices)
         dyStringAppend(gencodeQuery->where, " or ");
     filterBySupportLevelChoiceQuery(choice->name, gencodeQuery);
     }
 }
 
 static void filterBySupportLevelQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
 /* generate SQL where clause for annotation support level filtering */
 {
 gencodeQueryBeginSubWhere(gencodeQuery);
 filterBySupportLevelChoicesQuery(filterBy, gencodeQuery);
 gencodeQuery->joinSupportLevel = TRUE;
 gencodeQueryEndSubWhere(gencodeQuery);
 }
 
+static void filterByTagChoiceQuery(char *choice, struct gencodeQuery *gencodeQuery)
+/* add SQL expression GENCODE tag choice. */
+{
+dyStringPrintf(gencodeQuery->where, "(tag.tag = \"%s\")", choice);
+}
+
+static void filterByTagChoicesQuery(filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
+/* add tag compare clauses */
+{
+struct slName *choice = NULL;
+for (choice = filterBy->slChoices; choice != NULL; choice = choice->next)
+    {
+    if (choice != filterBy->slChoices)
+        dyStringAppend(gencodeQuery->where, " or ");
+    filterByTagChoiceQuery(choice->name, gencodeQuery);
+    }
+}
+
+static void filterByTagQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
+/* generate SQL where clause for annotation tag filtering */
+{
+gencodeQueryBeginSubWhere(gencodeQuery);
+filterByTagChoicesQuery(filterBy, gencodeQuery);
+gencodeQuery->joinTag = TRUE;
+gencodeQueryEndSubWhere(gencodeQuery);
+}
+
 static void filterByAttrsQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
 /* handle adding on filterBy clause for attributes table */
 {
 char *clause = filterByClause(filterBy);
 if (clause != NULL)
     {
     gencodeQueryBeginSubWhere(gencodeQuery);
     dyStringPrintf(gencodeQuery->where, "%s", clause);
     gencodeQuery->joinAttrs = TRUE;
     gencodeQueryEndSubWhere(gencodeQuery);
     freeMem(clause);
     }
 }
 
 static void gencodeFilterByQuery(struct track *tg, filterBy_t *filterBy, struct gencodeQuery *gencodeQuery)
 /* handle adding on filterBy clause for gencode */
 {
 if (sameString(filterBy->column, "transcriptMethod"))
     filterByMethodQuery(tg, filterBy, gencodeQuery);
 else if (sameString(filterBy->column, "supportLevel"))
     filterBySupportLevelQuery(tg, filterBy, gencodeQuery);
-else
+else if (sameString(filterBy->column, "tag"))
+    filterByTagQuery(tg, filterBy, gencodeQuery);
+else if (startsWith("attrs.", filterBy->column))
     filterByAttrsQuery(tg, filterBy, gencodeQuery);
+else
+    errAbort("gencodeFilterByQuery: don't know how to filter on column \"%s\"", filterBy->column);
 }
 
 static void gencodeFilterBySetQuery(struct track *tg, struct gencodeQuery *gencodeQuery)
 /* build where clause based on filters. */
 {
 filterBy_t *filterBySet = filterBySetGet(tg->tdb, cart, NULL);
 filterBy_t *filterBy;
 for (filterBy = filterBySet; filterBy != NULL; filterBy = filterBy->next)
     {
     if (!filterByAllChosen(filterBy))
         gencodeFilterByQuery(tg, filterBy, gencodeQuery);
     }
 filterBySetFree(&filterBySet);
 }
 
@@ -221,46 +258,58 @@
 }
 
 static void highlightByTranscriptTypeQuery(struct track *tg, filterBy_t *highlightBy, struct gencodeQuery *gencodeQuery)
 /* generate SQL where clause for obtaining transcript type for highlighting */
 {
 dyStringAppend(gencodeQuery->fields, ", attrs.transcriptType");
 gencodeQuery->transcriptTypeCol = gencodeQuery->nextFieldCol++;
 gencodeQuery->transcriptTypeHighlight = highlightBy;
 gencodeQuery->joinAttrs = TRUE;
 }
 
 
 static void highlightByTranscriptMethodQuery(struct track *tg, filterBy_t *highlightBy, struct gencodeQuery *gencodeQuery)
 /* generate SQL where clause for obtaining transcript type for highlighting */
 {
-gencodeQuery->joinTransSrc = TRUE;
+gencodeQuery->joinTranscriptSource = TRUE;
 dyStringAppend(gencodeQuery->fields, ", transSrc.source");
 gencodeQuery->transcriptSourceCol = gencodeQuery->nextFieldCol++;
 gencodeQuery->transcriptMethodHighlight = highlightBy;
 gencodeQuery->joinAttrs = TRUE;
 }
 
+static void highlightByTagQuery(struct track *tg, filterBy_t *highlightBy, struct gencodeQuery *gencodeQuery)
+/* generate SQL where clause for obtaining tag for highlighting */
+{
+gencodeQuery->joinTag = TRUE;
+dyStringAppend(gencodeQuery->fields, ", tag.tag");
+gencodeQuery->tagCol = gencodeQuery->nextFieldCol++;
+gencodeQuery->tagHighlight = highlightBy;
+gencodeQuery->joinTag = TRUE;
+}
+
 static void gencodeHighlightByQuery(struct track *tg, filterBy_t *highlightBy, struct gencodeQuery *gencodeQuery)
 /* Handle a highlight by category.  highlightBy object will be saved in gencodeQuery */
 {
 if (sameString(highlightBy->column, "supportLevel"))
     highlightBySupportLevelQuery(tg, highlightBy, gencodeQuery);
 else if (sameString(highlightBy->column, "attrs.transcriptType"))
     highlightByTranscriptTypeQuery(tg, highlightBy, gencodeQuery);
 else if (sameString(highlightBy->column, "transcriptMethod"))
     highlightByTranscriptMethodQuery(tg, highlightBy, gencodeQuery);
+else if (sameString(highlightBy->column, "tag"))
+    highlightByTagQuery(tg, highlightBy, gencodeQuery);
 else
     errAbort("BUG: gencodeHighlightByQuery unknown highlight column: \"%s\"", highlightBy->column);
 }
 
 static void gencodeHighlightBySetQuery(struct track *tg, struct gencodeQuery *gencodeQuery)
 /* build add join and fields to include to provide data for highlighting.  This results
  * in extra columns being returned. */
 {
 filterBy_t *highlightBySet = highlightBySetGet(tg->tdb, cart, NULL);
 filterBy_t *highlightBy;
 while ((highlightBy = slPopHead(&highlightBySet)) != NULL)
     {
     if (!filterByAllChosen(highlightBy))
         gencodeHighlightByQuery(tg, highlightBy, gencodeQuery);
     else
@@ -322,72 +371,88 @@
 static bool highlightByTranscriptMethodSelected(char **row, struct gencodeQuery *gencodeQuery)
 /* is the transcript type associated with this transcript selected? */
 {
 if (gencodeQuery->transcriptMethodHighlight != NULL)
     {
     struct slName *choice;
     for (choice = gencodeQuery->transcriptMethodHighlight->slChoices; choice != NULL; choice = choice->next)
         {
         if (highlightByTranscriptMethodMatch(choice->name, row[gencodeQuery->transcriptSourceCol]))
             return TRUE;
         }
     }
 return FALSE;
 }
 
+static bool highlightByTagSelected(char **row, struct gencodeQuery *gencodeQuery)
+/* is the tag associated with this transcript selected? */
+{
+if (gencodeQuery->tagHighlight == NULL)
+    return FALSE;  // no highlighting by tag
+else
+    return slNameInList(gencodeQuery->tagHighlight->slChoices, row[gencodeQuery->tagCol]);
+}
+
 static unsigned getHighlightColor(struct track *tg)
 /* get the highlightColor from trackDb, or a default if not found */
 {
 unsigned char red = 255, green = 165, blue = 0; // Orange default
 char *colorStr = trackDbSetting(tg->tdb, "highlightColor");
 if (colorStr != NULL)
     parseColor(colorStr, &red, &green, &blue);
 return MAKECOLOR_32(red, green, blue);
 }
 
 static void highlightByGetColor(char **row, struct gencodeQuery *gencodeQuery, unsigned highlightColor,
                                 struct linkedFeatures *lf)
 /* compute the highlight color based on a extra fields returned in a row, setting
  * the linkedFeatures field */
 {
-if (highlightBySupportLevelSelected(row, gencodeQuery) || highlightByTranscriptTypeSelected(row, gencodeQuery)
-    || highlightByTranscriptMethodSelected(row, gencodeQuery))
+if (highlightBySupportLevelSelected(row, gencodeQuery)
+    || highlightByTranscriptTypeSelected(row, gencodeQuery)
+    || highlightByTranscriptMethodSelected(row, gencodeQuery)
+    || highlightByTagSelected(row, gencodeQuery))
     {
     lf->highlightColor = highlightColor;
     lf->highlightMode = highlightBackground;
     }
 }
 
 static void addQueryTables(struct track *tg, struct gencodeQuery *gencodeQuery)
 /* add required from tables and joins */
 {
 sqlDyStringPrintfFrag(gencodeQuery->from, "%s g", tg->table);
 if (gencodeQuery->joinAttrs)
     {
     sqlDyStringPrintf(gencodeQuery->from, ", %s attrs", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeAttrs"));
     dyStringAppend(gencodeQuery->where, " and (attrs.transcriptId = g.name)");
     }
-if (gencodeQuery->joinTransSrc)
+if (gencodeQuery->joinTranscriptSource)
     {
     sqlDyStringPrintf(gencodeQuery->from, ", %s transSrc", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTranscriptSource"));
     dyStringAppend(gencodeQuery->where, " and (transSrc.transcriptId = g.name)");
     }
 if (gencodeQuery->joinSupportLevel)
     {
     sqlDyStringPrintf(gencodeQuery->from, ", %s supLevel", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTranscriptionSupportLevel"));
     dyStringAppend(gencodeQuery->where, " and (supLevel.transcriptId = g.name)");
     }
+if (gencodeQuery->joinTag)
+    {
+    sqlDyStringPrintf(gencodeQuery->from, ", %s tag", trackDbRequiredSetting(tg->tdb, "wgEncodeGencodeTag"));
+    dyStringAppend(gencodeQuery->where, " and (tag.transcriptId = g.name)");
+    }
 }
 
 static boolean tableIsGenePredX(struct track *tg)
 /* determine if a table has genePred extended fields.  two-way consensus
  * pseudo doesn't have them. */
 {
 struct sqlConnection *conn = hAllocConn(database);
 struct slName *fields = sqlFieldNames(conn, tg->table);
 hFreeConn(&conn);
 boolean isGenePredX = slNameInList(fields, "score");
 slFreeList(&fields);
 return isGenePredX;
 }
 
 static struct gencodeQuery *gencodeQueryConstruct(struct track *tg)