1f1b38c1c05c0e0011260a38a9eb926cd6038afd
max
  Tue Mar 12 14:00:43 2013 -0700
new pubsBlat format allows to specify mouseover text and labels as part of primary table, without join. Also allows to define classes of papers and color them via a second table
diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 13b5b4a..252695d 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -1,28 +1,29 @@
 /* infrastructure -- Code shared by all tracks.  Separating this out from
  * hgTracks.c allows a standalone main to make track images. */
 
 /* NOTE: This code was imported from hgTracks.c 1.1469, May 19 2008,
  * so a lot of revision history has been obscured.  To see code history
  * from before this file was created, run this:
  * cvs ann -r 1.1469 hgTracks.c | less +Gp
  */
 
 #include "common.h"
 #include "spaceSaver.h"
 #include "portable.h"
 #include "bed.h"
+#include "basicBed.h"
 #include "psl.h"
 #include "web.h"
 #include "hdb.h"
 #include "hgFind.h"
 #include "hCommon.h"
 #include "hgColors.h"
 #include "trackDb.h"
 #include "bedCart.h"
 #include "wiggle.h"
 #include "lfs.h"
 #include "grp.h"
 #include "chromColors.h"
 #include "hgTracks.h"
 #include "subText.h"
 #include "cds.h"
@@ -12076,95 +12077,191 @@
     ; while(*str)
     {
     matchStr[i++] = '+';
     for(; *str && !isspace(*str);str++)
         matchStr[i++] = *str;
     for(;*str && isspace(*str);str++)
         ;
     }
 matchStr[i++] = 0;
 return matchStr;
 }
 
 struct pubsExtra 
 /* additional info needed for publication blat linked features: author+year and title */
 {
-    char* label;
-    char* mouseOver;
+    char *label; // usually author+year
+    char *mouseOver; // usually title of article
+    // color depends on cart settings, either based on topic, impact or year
+    // support to ways to color: either by shade (year, impact) or directly with rgb values
+    int shade;  // year or impact are shades which we can't resolve to rgb easily
+    struct rgbColor *color; 
 };
 
+/* assignment of pubs classes to colors */
+static struct hash* pubsClassColors = NULL;
+
+static void pubsParseClassColors() 
+/* parse class colors from hgFixed.pubsClassColors into the hash pubsClassColors */
+{
+if (pubsClassColors!=NULL)
+    return;
+
+pubsClassColors = hashNew(0);
+struct sqlConnection *conn = hAllocConn(database);
+if (!sqlTableExists(conn, "hgFixed.pubsClassColors")) 
+    {
+    //fprintf(stderr, "simpleTracks.c: table hgFixed.pubsClassColors does not exist\n");
+    return;
+    }
+char *query = "SELECT class, rgbColor FROM hgFixed.pubsClassColors";
+struct sqlResult *sr = sqlGetResult(conn, query);
+char **row = NULL;
+if ((row = sqlNextRow(sr)) != NULL)
+    {
+    char *class = row[0];
+    char *colStr = row[1];
+    // copied from genePredItemClassColor - is there no function for this?
+    char *rgbVals[5];
+    chopString(colStr, ",", rgbVals, sizeof(rgbVals));
+    struct rgbColor *rgb;
+    AllocVar(rgb);
+    rgb->r = (sqlUnsigned(rgbVals[0]));
+    rgb->g = (sqlUnsigned(rgbVals[1]));
+    rgb->b = (sqlUnsigned(rgbVals[2]));
+    //printf("Adding hash: %s -> %d,%d,%d", class, rgb->r, rgb->g, rgb->b);
+    hashAdd(pubsClassColors, cloneString(class), rgb);
+    }
+sqlFreeResult(&sr);
+}
+
 static char* pubsFeatureLabel(char* author, char* year) 
 /* create label <author><year> given authors and year strings */
 {
 char* authorYear = NULL;
 
 if (isEmpty(author))
     author = "NoAuthor";
 if (isEmpty(year))
     year = "NoYear";
 authorYear  = catTwoStrings(author, year);
 
 return authorYear;
 }
 
-static struct pubsExtra *pubsMakeExtra(char* articleTable, struct sqlConnection* conn, 
-    struct linkedFeatures* lf)
+static struct pubsExtra *pubsMakeExtra(struct track* tg, char* articleTable, 
+    struct sqlConnection* conn, struct linkedFeatures* lf)
+/* bad solution: a function that is called before the extra field is 
+ * accessed and that fills it from a sql query. Will need to redo this like gencode, 
+ * drawing from atom, variome and bedLoadN or bedDetails */
 {
 char query[LARGEBUF];
 struct sqlResult *sr = NULL;
 char **row = NULL;
 struct pubsExtra *extra = NULL;
 
+/* support two different storage places for article data: either the bed table directly 
+ * includes the title + author of the article or we have to look it up from the articles 
+ * table. Having a copy of the title in the bed table is faster */
+bool newFormat = false;
+if (sqlColumnExists(conn, tg->table, "title")) 
+    {
+    safef(query, sizeof(query), "SELECT firstAuthor, year, title, impact, classes FROM %s "
+    "WHERE chrom = '%s' and chromStart = '%d' and name='%s'", tg->table, chromName, lf->start, lf->name);
+    newFormat = true;
+    }
+else 
+    {
 safef(query, sizeof(query), "SELECT firstAuthor, year, title FROM %s WHERE articleId = '%s'", 
     articleTable, lf->name);
+    newFormat = false;
+    }
+
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
 {
     char* firstAuthor = row[0];
     char* year    = row[1];
     char* title   = row[2];
+    char* impact  = NULL;
+    char* classes = NULL;
 
     extra = needMem(sizeof(struct pubsExtra));
     extra->label = pubsFeatureLabel(firstAuthor, year);
     if (isEmpty(title))
         extra->mouseOver = extra->label;
     else
         extra->mouseOver = cloneString(title);
+    extra->color  = NULL;
+    extra->shade  = -1;
+
+    if (newFormat) 
+        {
+        impact  = row[3];
+        classes = row[4];
+        if (!isEmpty(impact)) 
+            {
+            char *colorBy = cartOptionalStringClosestToHome(cart, tg->tdb, FALSE, "pubsColorBy");
+            if (strcmp(colorBy,"impact")==0) 
+                {
+                char impInt = atoi(impact);
+                extra->shade = impInt/25;
+                }
+            if (strcmp(colorBy,"year")==0) 
+                {
+                int relYear = (atoi(year)-1990); 
+                extra->shade = min(relYear/3, 10);
+                //extra->color = shadesOfGray[yearShade];
+                }
+            if (strcmp(colorBy,"topic")==0) 
+                {
+                char *class;
+                while ((class=cloneNextWordByDelimiter(&classes, ','))!=NULL)
+                    {
+                    struct rgbColor *col = (struct rgbColor*) hashFindVal(pubsClassColors, class);
+                    extra->color = col;
+                    }
+                }
+
+            }
+        }
 }
 
+
 sqlFreeResult(&sr);
 return extra;
 }
 
 static void pubsAddExtra(struct track* tg, struct linkedFeatures* lf)
 /* add authorYear and title to linkedFeatures->extra */
 {
 char *articleTable = trackDbSettingClosestToHome(tg->tdb, "pubsArticleTable");
 if(isEmpty(articleTable))
     return;
 if (lf->extra != NULL)
     return;
 
 struct sqlConnection *conn = hAllocConn(database);
-struct pubsExtra* extra = pubsMakeExtra(articleTable, conn, lf);
+struct pubsExtra* extra = pubsMakeExtra(tg, articleTable, conn, lf);
 lf->extra = extra;
 hFreeConn(&conn);
 }
 
 static void pubsLoadKeywordYearItems(struct track *tg)
 /* load items that fulfill keyword and year filter */
 {
+pubsParseClassColors();
 struct sqlConnection *conn = hAllocConn(database);
 char *keywords = cartOptionalStringClosestToHome(cart, tg->tdb, FALSE, "pubsKeywords");
 char *yearFilter = cartOptionalStringClosestToHome(cart, tg->tdb, FALSE, "pubsYear");
 char *articleTable = pubsArticleTable(tg);
 
 if(yearFilter == NULL || sameWord(yearFilter, "anytime"))
     yearFilter = NULL;
 
 if(isNotEmpty(keywords))
     keywords = makeMysqlMatchStr(sqlEscapeString(keywords));
 
 if(isEmpty(yearFilter) && isEmpty(keywords))
 {
     loadGappedBed(tg);
 }
@@ -12222,30 +12319,50 @@
  * into the cart and activate the track.
  */
 {
 char *articleId = cgiOptionalString(PUBSFILTERNAME);
 //if (articleId==NULL) 
     //articleId = cartOptionalString(cart, PUBSFILTERNAME);
 
 if (articleId!=NULL) 
 {
     cartSetString(cart, PUBSFILTERNAME, articleId);
     tdbSetCartVisibility(tg->tdb, cart, hCarefulTrackOpenVis(database, tg->track));
     tg->visibility=tvPack;
 }
 }
 
+Color pubsItemColor(struct track *tg, void *item, struct hvGfx *hvg)
+/* get color from extra field */
+{
+//pubsParseClassColors();
+struct linkedFeatures *lf = item;
+pubsAddExtra(tg, lf);
+
+struct pubsExtra* extra = lf->extra;
+if (extra==NULL || (extra->color==NULL && extra->shade==-1))
+    return MG_BLACK;
+
+if (extra->shade != -1)
+    return shadesOfBlue[extra->shade];
+else
+    {
+    //printf("got item color %d", extra->color->r);
+    return hvGfxFindRgb(hvg, extra->color);
+    }
+}
+
 char *pubsItemName(struct track *tg, void *item)
 /* get author/year from extra field */
 {
 struct linkedFeatures *lf = item;
 pubsAddExtra(tg, lf);
 
 struct pubsExtra* extra = lf->extra;
 if (extra!=NULL)
     return extra->label;
 else
     return lf->name;
 
 }
 
 static void pubsMapItem(struct track *tg, struct hvGfx *hvg, void *item,
@@ -12376,30 +12493,31 @@
 static void pubsBlatPslMethods(struct track *tg)
 /* a track that shows only the indiv matches for one single article */
 {
 activatePslTrackIfCgi(tg);
 tg->loadItems = pubsPslLoadItems;
 tg->itemName  = pubsItemName;
 tg->mapItem   = pubsMapItem;
 }
 
 static void pubsBlatMethods(struct track *tg)
 /* publication blat tracks are bed12+2 tracks of sequences in text, mapped with BLAT */
 {
 //bedMethods(tg);
 tg->loadItems = pubsLoadKeywordYearItems;
 tg->itemName  = pubsItemName;
+tg->itemColor = pubsItemColor;
 tg->mapItem   = pubsMapItem;
 }
 
 static void pubsMarkerMethods(struct track *tg)
 /* publication marker tracks are bed5 tracks of genome marker occurences like rsXXXX found in text*/
 {
 tg->mapItem   = pubsMarkerMapItem;
 tg->itemName  = pubsMarkerItemName;
 }
 
 void fillInFromType(struct track *track, struct trackDb *tdb)
 /* Fill in various function pointers in track from type field of tdb. */
 {
 char *typeLine = tdb->type, *words[8], *type;
 int wordCount;