src/hg/instinct/hgHeatmap/mainPage.c 1.71

1.71 2009/08/19 23:00:17 angie
Added option to mgSaveToGif and its call stack, to use GIF's Graphic Control Extension to make memgfx's background color (0) transparent. Also corrected terminology for PNG in .h files: useAlpha -> useTransparency.
Index: src/hg/instinct/hgHeatmap/mainPage.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/instinct/hgHeatmap/mainPage.c,v
retrieving revision 1.70
retrieving revision 1.71
diff -b -B -U 1000000 -r1.70 -r1.71
--- src/hg/instinct/hgHeatmap/mainPage.c	19 Nov 2008 06:35:59 -0000	1.70
+++ src/hg/instinct/hgHeatmap/mainPage.c	19 Aug 2009 23:00:17 -0000	1.71
@@ -1,3381 +1,3381 @@
 /* mainPage - drs the main hgHeatmap page, including some controls
  * on the top and the graphic. */
 
 #define EXPR_DATA_SHADES 16
 #define DEFAULT_MAX_DEVIATION 0.7
 #define COLOR_SCALE 1
 #define MAX_PCA_COMPONENTS 2
 
 #include "common.h"
 #include "hgHeatmap.h"
 #include "chromGraph.h"
 #include "bed.h"
 #include "cart.h"
 #include "customTrack.h"
 #include "errCatch.h"
 #include "genoLay.h"
 #include "trackLayout.h"
 #include "hash.h"
 #include "hdb.h"
 #include "hgColors.h"
 #include "hPrint.h"
 #include "htmshell.h"
 #include "jsHelper.h"
 #include "psGfx.h"
 #include "trashDir.h"
 #include "vGfx.h"
 #include "hvGfx.h"
 #include "web.h"
 #include "cytoBand.h"
 #include "hCytoBand.h"
 #include "hgHeatmapLib.h"
 #include "hgChromGraph.h"
 #include "heatmapUtility.h"
 #include "featuresLib.h"
 #include "hgStats.h"
 #include "filterFeatures.h"
 #include "hgStatsLib.h"
 
 static char const rcsid[] = "$Id$";
 
 extern enum  testType { diffAve, ttestT, wilcoxonT, ecScore,fishersExactT, fishersLinearDiscT, jarqueBeraT, leveneHOV, brownForsytheHOV }  testType;
 extern char *statTest[];
 extern enum  blockTestType { pca, fisher,weightedZ }  blockTestType;
 extern char *blockStatTest[];
 extern enum  metaTestType { metaTestFisherMeta,metaTestStoufferMeta,metaTestMudholkarMeta,metaTestSymmUniMeta }  metaTestType;
 extern char *metaStatTest[];
 
 extern struct analysisResult *ghMetaResult;         /* meta analysis results in chromosomal view */
 extern struct analysisResultHash *ghMetaResultHash; /* meta analysis results in genesets view */
 
 int doClustering()
 {
 if (getClusterMethod() == 'x')
     return 0;
 
 return 1;
 }
 
 struct hash *getProbeAliases(char *db, char *tableName)
 {
 if (tableName == NULL)
     return NULL;
 
 char query[512];
 safef(query, sizeof(query), 
       "select * from %s ", tableName);
 
 struct sqlConnection *conn = hAllocConn(db);  
 struct sqlResult *sr = sqlGetResult(conn, query);
 
 char **row = NULL;
 char *name, *alias;
 struct hash *probeHash = hashNew(0);
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     name = cloneString(row[0]);
     alias = cloneString(row[1]);
 
     hashAdd(probeHash, name, alias);
     }
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 
 return probeHash;
 }
 
 #define CLIP(p,limit) if (p < 0) p = 0; if (p >= (limit)) p = (limit)-1;
 static void verticalTextCentered(struct vGfx *vg, int x, int y,
 				 int width, int height, int colorIx, MgFont *font, char *string)
 /* Draw a vertical line of text in middle of the box.
  *      The string will read from bottom to top
  * This is not perfect by any means, but seems to draw the labels fairly nice
  * for the pathways. 
  */
 {
 /*      don't let this run wild */
 CLIP(width, vg->width);
 CLIP(height, vg->height);
 
 if ((width > 0) && (height > 0))
     {
     struct vGfx *vgHoriz;
     int i, j;
     /*  reversed meanings of width and height here since this is going
      *  to rotate 90 degrees
     */
     int offset = 0;
     int cutoff = height / 7;  // TODO, approximately correct.
     int lineSpacing = 15;
 
-    vgHoriz = vgOpenGif(height, width, "/dev/null");
+    vgHoriz = vgOpenGif(height, width, "/dev/null", FALSE);
     struct slName *sl, *slList = slNameListFromString(string, '_');
 
     struct dyString *dy = newDyString(0), *dyList = NULL;
     for (sl = slList; sl; sl = sl->next)
 	{ /* loop through words in text, separated by underscores */
 	if ( (dy->stringSize > 0) && (offset < width) && 
 	     (dy->stringSize + strlen(sl->name) > cutoff))
 	    { /* enough string for a single line is ready to be drawn and can be drawn */
 	    slAddHead(&dyList, dy);
 	    dy = newDyString(0);
 	    offset += lineSpacing;
 	    }
 	dyStringAppend(dy, sl->name);
         dyStringAppend(dy, " ");
 	}
     
     if ( (dy->stringSize > 0) && (offset < width) )
 	/* Clean up remaining string */
 	slAddHead(&dyList, dy);
 
     slReverse(&dyList);
     int count = slCount(dyList);
 
     offset = 0;
     for (dy = dyList; dy ; dy = dy->next)
 	{ /* -3 is needed to approximately recenter text */ 
 	vgTextCentered(vgHoriz, 0, -3*(count - 1), height, width+offset, 
 		       colorIx, font, dy->string);
 	offset += lineSpacing;
 	}
 
     dyStringFreeList(&dyList);
 
     /*  now, blit from the horizontal to the vertical, rotate -90 (CCW) */
     for (i = 0; i < height; ++i)        /* xSrc -> yDest */
         {
         int yDest = height - i;
         for (j = 0; j < width; ++j)     /* ySrc -> xDest */
             vgDot(vg, j+x, yDest+y, vgGetDot(vgHoriz, i, j));
      
         }
     vgClose(&vgHoriz);
     }
 }
 
 void drawGeneSetLabel(struct genoLay *gl, struct geneSet *gs,
 		      struct hvGfx *vg, int color, boolean vertical)
 /* Draw single geneset labels in image, 
    the argument "vertical" defines if the label will be drew vertically, or horizontally */
 {
 int height = hghGeneSetLabel; 
 int yOffset = gl->chromOffsetY + gl->chromHeight;
 if (vertical)
     verticalTextCentered(vg->vg, gs->x, yOffset, gs->width, height, color, gl->font,
 			 gs->displayName);
 else
     hvGfxTextCentered(vg,gs->x,yOffset,gs->width, height, MG_BLACK,
 		      gl->font,gs->displayName);
 }
 
 void drawGeneSetLabels(struct genoLay *gl, struct geneSet *geneSets, 
 		       struct hvGfx *vg, int color)
 /* Draw all displayed gene set labels in image */
 {
 struct geneSet *gs;
 int count=0;
 for (gs = geneSets; gs; gs = gs->next)
     count++;
 
 int verThr = 3;
 for (gs = geneSets; gs; gs = gs->next)
     {
     if (count <= verThr)
 	drawGeneSetLabel(gl, gs, vg, color, FALSE);
     else
 	drawGeneSetLabel(gl, gs, vg, color, TRUE);
     }
 }
 
 void drawGeneSetBand(struct genoLay *gl, struct geneSet *gs,
                      struct hvGfx *vg, int color)
 /* Draw box for single gene set in given color */
 {
 int height = gl->chromHeight;
 int yOffset = gl->chromOffsetY +1;
 vgBox(vg->vg, gs->x, gs->y + yOffset, gs->width, height, color);
 }  
 
 void drawGeneSetBands(struct genoLay *gl, struct geneSet *geneSets,
 		      struct hvGfx *vg, int color)
 /* Draw boxes for all displayed gene sets in given color */
 {
 struct geneSet *gs;
 for (gs = geneSets; gs; gs = gs->next)
     drawGeneSetBand(gl, gs, vg, color);
 }    
 
 
 void geneSetOneRowLayout(struct geneSet *gs, struct hash *geneHash, int numSegment)
 {
 /* layout for one pathway per row , numSegment is the number of segment the row is divided 
  * typically, each segment display one type of data 
  */
 if (gs == NULL || geneHash == NULL)
     return; 
 
 int picWidth = cartUsualInt(cart, hghImageWidth, hgHeatmapDefaultPixWidth) / numSegment; 
 gs->x = picWidth;
 gs->y = 0;
 gs->width = picWidth;
 
 struct slName *sl;
 int numActive = 0;
 for (sl = gs->genes; sl ; sl = sl->next)
     {
     struct hashEl *el = hashLookup(geneHash, sl->name);
     while (el)
 	{
 	numActive++;
 	el = hashLookupNext(el);
 	}
     }
 gs->numGenesActive = numActive;
 gs->pixelsPerGene = (double) gs->width / (double) gs->numGenesActive;
 }
 
 void geneSetsAddPathwayLayout(struct geneSet *geneSets, struct hash *geneHash)
 {
 /* lay out of all pathways, add setting the gs->pixelsPerGene gs->activeNum for each gene */
 if (geneSets == NULL || geneHash == NULL)
     return;
 
 struct geneSet *gs;
 for (gs = geneSets; gs; gs = gs->next)
     {
     struct slName *sl;
     int numActive = 0;
     for (sl = gs->genes; sl ; sl = sl->next)
 	{
 	struct hashEl *el = hashLookup(geneHash, sl->name);
 	while (el)
 	    {
 	    numActive++;
 	    el = hashLookupNext(el);
 	    }
 	}
     gs->numGenesActive = numActive;
     gs->pixelsPerGene = (double) gs->width / (double) gs->numGenesActive;
     }
 }
 
 void geneSetsChromLayout(struct geneSet *geneSets)
 /* lay out of all pathways similar to chromsomes, 
    without setting the gs->pixelsPerGene gs->activeNum for each gene */
 {
 if (geneSets == NULL)
     return;
 
 int totalGenes = 0;
 struct geneSet *gs;
 int numSets = 0;
 
 for (gs = geneSets; gs; gs = gs->next)
     {
     totalGenes += gs->numGenes;
     numSets++;
     }
 if (totalGenes == 0)
     return;
 
 int picWidth = cartUsualInt(cart, hghImageWidth, hgHeatmapDefaultPixWidth);
 
 double xOff = 3;
 int minWidth = 20;
 
 int totalW = (double) (picWidth - numSets);
 for (gs = geneSets; gs; gs = gs->next)
     {
     int w = gs->numGenes * (picWidth - numSets) / totalGenes;
     if (w  < minWidth)
 	{
 	totalGenes -= gs->numGenes;
 	totalW -= minWidth;
 	}
     }
 
 /* 5 is hard-coded , it works well*/
 double pixelsPerGene = (totalW - 5 ) / (double) totalGenes;
 for (gs = geneSets; gs; gs = gs->next)
     {
     gs->x = (int) xOff;
     gs->y = 0;
     gs->width = (int) (gs->numGenes * pixelsPerGene);
 
     if (gs->width < minWidth)
 	gs->width = minWidth;
     xOff += (double) gs->width + 1.0; 
     }
 }
 
 
 struct chromGraph *getChromGraph (char* database, char* tableName, char* chromName)
 /* get chromGraph data for each chromosome */
 {
 if (tableName == NULL)
     return NULL;
 
 /* get the data from the database */
 char **row = NULL;
 char query[512];
 query[0] = '\0';
 
 if (chromName)
     {
     safef(query, sizeof(query),
 	  "select * from %s where chrom = \"%s\" \n",
 	  tableName, chromName);
     }
 else
     { /* No chromosome specified, default to full genome */
     safef(query, sizeof(query),
 	  "select * from %s \n",
 	  tableName);
     }
 
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr = sqlGetResult(conn, query);
 struct chromGraph *tuple = NULL;
 struct chromGraph *tupleList = NULL;
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     tuple = chromGraphLoad(row);
     slAddHead(&tupleList, tuple);
     }
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 return tupleList;
 }
 
 struct bed *getBedGraph (char* database, char* tableName, char* chromName, int nField)
 /* get bedGraph data for each chromosome */
 {
 if (tableName == NULL)
     return NULL;
 
 /* get the data from the database */
 char **row = NULL;
 char query[512];
 query[0] = '\0';
 
 if (chromName)
     {
     safef(query, sizeof(query),
 	  "select * from %s where chrom = \"%s\" \n",
 	  tableName, chromName);
     }
 else
     { /* No chromosome specified, default to full genome */
     safef(query, sizeof(query),
 	  "select * from %s \n",
 	  tableName);
     }
 
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr = sqlGetResult(conn, query);
 struct bed *tuple = NULL;
 struct bed *tupleList = NULL;
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     tuple = bedLoadN(row+1,nField);
     slAddHead(&tupleList, tuple);
     }
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 return tupleList;
 }
 
 /* return an array for reordering the experiments in a chromosome */
 double maxDeviation(char* heatmap)
 {
 struct hashEl *e = hashLookup(ghHash, heatmap);
 
 if (!e)
     errAbort("Could not found heatmap %s\n", heatmap);
 
 struct genoHeatmap *gh = e->val;
 if (gh->expScale >0)
     return gh->expScale;
 
 return DEFAULT_MAX_DEVIATION;
 }
 
 
 void vgMakeColorGradient(struct vGfx *vg,
     struct rgbColor *start, struct rgbColor *end,
     int steps, Color *colorIxs)
 /* Make a color gradient that goes smoothly from start
  * to end colors in given number of steps.  Put indicesgl->chromLis
  * in color table in colorIxs */
 {
 double scale = 0, invScale;
 double invStep;
 int i; int r,g,b;
 
 steps -= 1;     /* Easier to do the calculation in an inclusive way. */
 invStep = 1.0/steps;
 for (i=0; i<=steps; ++i)
     {
     invScale = 1.0 - scale;
     r = invScale * start->r + scale * end->r;
     g = invScale * start->g + scale * end->g;
     b = invScale * start->b + scale * end->b;
     colorIxs[i] = vgFindColorIx(vg, r, g, b);
     scale += invStep;
     }
 }
 
 
 void drawGeneLabels(struct vGfx *vg,  struct genoLay *gl, char *chromHeatmap,
 		    struct geneSet *allGeneSets, struct hash *geneHash, int yOff)
 {
 if (!allGeneSets || !geneHash)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 struct hash *displayNameHash = getProbeAliases(database, gh->displayNameTable);
 
 struct geneSet *gs;
 double height = hghGeneLabelHeight;
 int x,y,w,h;
 struct slName *sl;
 for (gs = allGeneSets; gs; gs = gs->next)
     {
     int count=0;
     struct slName *geneOrder = NULL;
 
     char method = getClusterMethod();
     char metric = getClusterMetric();
 
     if(doClustering())
 	geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);   //ordering inside gene set
     if (!geneOrder)
 	geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
     int gsX = gs->x, gsY = gs->y;
     y = gsY +yOff;
     w = ceil(gs->pixelsPerGene);
     h= height;   
     for (sl = geneOrder; sl ; sl = sl->next)
 	{
 	el = hashLookup(geneHash, sl->name);
 	if (!el)
 	    continue;
 
 	char *displayName = sl->name;
 	if (displayNameHash)
 	    {
 	    struct hashEl *hl = hashLookup(displayNameHash, sl->name);
 	    if (hl)
 		displayName = hl->val;
 	    }
 
 	int sameGeneCount =0;
 	boolean probeLevelDraw = FALSE;
 	while (el)  // for >= one probe
 	    {
 	    if (gs->pixelsPerGene > hghGeneLabelMinSize) // enough space to draw for each probe /////////
 		{
 		x = (int) ( gs->pixelsPerGene * (double) (count) + gsX );
 		verticalTextCentered(vg, x, y, w, h, MG_BLACK, gl->font, displayName);
 		probeLevelDraw = TRUE;
 		}
 	    count++;
 	    sameGeneCount++;
 	    el = hashLookupNext(el);
 	    }
 
 	if (!probeLevelDraw) // there is too little space to show gene labels for each probe
 	    {
 	    x = (int) ( gs->pixelsPerGene * (double) (count - sameGeneCount) + gsX );
 	    w = gs->pixelsPerGene * sameGeneCount;
 	    char printout[128];
 	    if (sameGeneCount >1)
 		safef(printout, sizeof(printout),"%s(%d)", sl->name, sameGeneCount);
 	    else 
 		safef(printout, sizeof(printout),"%s", displayName);
 	    verticalTextCentered(vg, x, y, w, h, MG_BLACK, gl->font, printout);
 	    }
 	}
     }
 }
 
 void drawGeneSetBlockStat(struct vGfx *vg, struct hash *statHash, struct geneSet *gs, 
 			  int yOff, double gMin, double gMax, float colorCutoff)
 {
 if (!statHash | !gs)
     return;
 
 
 Color valCol;
 double height = hghBed5Height;
 double baseline = (float) height /2.0;
 double gScale = height/(gMax-gMin) /2.0;
 float val, dirVal;
 int x;
 int y1,y2;
 int w, h;
         
 struct hashEl *el = hashLookup(statHash, gs->name);
 while (el)
     {
     struct hgStats *nb = el->val;
     int totalComps = nb->totalComps;
     int compIndex = nb->compIndex;
 
     el = hashLookupNext(el);
 
     if (compIndex >= MAX_PCA_COMPONENTS)
 	continue;
 
     int gsX = gs->x, gsY = gs->y;
     
     if (totalComps > MAX_PCA_COMPONENTS)
 	totalComps = MAX_PCA_COMPONENTS;
 
     w = ceil(gs->width / (double) totalComps);
     x = gsX + ceil((double) compIndex * gs->width / (double) totalComps);
     
     val = fabs(nb->prob);
     dirVal = nb->stats;
     
     if (val > gMax)
 	val = gMax;
     if (val < gMin)
 	val = gMin;
     
     if (val < colorCutoff)
 	valCol = MG_GRAY;
     else if (dirVal > 0)
 	valCol = MG_RED;
     else 
 	valCol = MG_GREEN;
     
     if (dirVal > 0)
 	{
 	y1 = baseline  - val*gScale  + gsY + yOff; //smaller value
 	y2 = baseline + gsY + yOff; //greater value
 	h = y2-y1;
 	
 	/* sometimes if the bed segment is too small, resulting in width=0, 
 	   reset to 1 pixel length */
 	if ((w ==0) && (h != 0)) 
 	    w=1;
 	if (w && h)
 	    vgBox(vg, x, y1, w, h, valCol);
 	}
     else
 	{
 	y1 = baseline + val *gScale + gsY + yOff; //greater value
 	y2 = baseline + gsY + yOff; //smaller value 
 	h = y1-y2;
 	/* sometimes if the bed segment is too small, resulting in width=0, 
 	   reset to 1 pixel length */
 	if ((w ==0) && (h != 0))
 	    w=1;
 	if (w && h)
 	    vgBox(vg, x, y2, w, h, valCol);
 	}
 
     }
     
 }
 
 void drawGeneSetSingleStat(struct vGfx *vg, struct hash *statHash, struct geneSet *gs, 
 			   int yOff, double gMin, double gMax, float colorCutoff,
 			   char *chromHeatmap, struct hash *geneHash)
 {
 if (!statHash | !gs)
     return;
 
 int gsX = gs->x, gsY = gs->y;
 
 Color valCol;
 double height = hghBed5Height;
 double baseline = (float) height /2.0;
 double gScale = height/(gMax-gMin) /2.0;
 float val, dirVal;
 int x;
 int y1,y2;
 int w, h;
 
 double count = 0.0;
 struct slName *sl;
 struct slName *geneOrder = NULL;
 
 char method = getClusterMethod();
 char metric = getClusterMetric();
 
 if (doClustering() && !chromHeatmap && !geneHash )
     geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);   
 //ordering inside gene set
 
 if (geneOrder == NULL)
     geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
 for (sl = geneOrder; sl ; sl = sl->next)
     {
     struct hgStats *nb=NULL;
     struct hashEl *el;
     
     el = hashLookup(statHash, sl->name);
     
     while (el)  // maybe more than one probe?
 	{
 	nb = el->val;
 	x = (int) ( gs->pixelsPerGene * count + gsX ); // get the X position
 	w = ceil(gs->pixelsPerGene);
 	val = fabs(nb->prob);
 	dirVal = nb->stats;
 	
 	if (val>gMax)
 	    val = gMax;
 	if (val <gMin)
 	    val = gMin;
 	
 	if (val < colorCutoff)
 	    valCol = MG_GRAY;
 	else if (dirVal >0)
 	    valCol = MG_RED;
 	else 
 	    valCol = MG_GREEN;
 	
 	if (dirVal>0)
 	    {
 	    y1 = baseline  - val *gScale  + gsY + yOff; //smaller value
 	    y2 = baseline + gsY + yOff; //greater value
 	    h = y2-y1;
 	    
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0)) 
 		w=1;
 	    if (w && h)
 		vgBox(vg,x,y1, w, h,valCol);
 	    }
 	else
 	    {
 	    y1 = baseline + val *gScale + gsY + yOff; //greater value
 	    y2 = baseline + gsY + yOff; //smaller value 
 	    h = y1-y2;
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0))
 		w=1;
 	    if (w && h)
 		vgBox(vg,x,y2,w,h,valCol);
 	    }
 	
 	count++;
 	el = hashLookupNext(el);
 	}
     }
 }
 
 
 /* Draw hgStats results along gene sets  */
 void drawGeneSetHgStats(struct vGfx *vg, struct hash *statHash, 
 			struct genoLay *gl, int yOff, struct geneSet *geneSets, 
 			double gMin, double gMax, float colorCutoff, boolean isBlockStat,
 			char *tableName, struct hash *geneHash)
 /* Drawing code */
 {
 if (!statHash)
     errAbort("no hgStats results \n");
 
 if (!geneSets)
     return;
 
 // layout
 if (isBlockStat)
     geneSetsAddPathwayLayout(geneSets, NULL); 
 else
     geneSetsAddPathwayLayout(geneSets, statHash);
 
 struct geneSet *gs;
 for (gs = geneSets; gs ; gs = gs->next)
     {
     if (isBlockStat)
 	drawGeneSetBlockStat(vg, statHash, gs, yOff, gMin, gMax, colorCutoff);
     else
 	drawGeneSetSingleStat(vg, statHash, gs, yOff, gMin, gMax, colorCutoff, tableName, geneHash);
     }
 }                                                
 
 
 
 /* draw probility score according to chrom position in list of hgStats, 
  * the display direction (positive/red/above baseline, negative/greeen/below baseline
  * is controlled by the stats field */
 void drawHgStats (struct vGfx *vg, struct hgStats *bg, struct genoLay *gl, 
 		  int yOff, double gMin, double gMax, double colorCutoff)
 {
 if (!bg)
     return;
 
 /* Chromosome layout hashs */
 struct genoLayChrom *chrom=NULL;
 struct hash *chromHashX= newHash(0);
 struct hash *chromHashY= newHash(0);
 for(chrom = gl->chromList; chrom; chrom = chrom->next)
     {
     int chromX = chrom->x, chromY = chrom->y;
     char *name = chrom->fullName;
     hashAddInt(chromHashX, name, chromX); 
     hashAddInt(chromHashY, name, chromY) ;
     }
 
 double pixelsPerBase = 1.0/gl->basesPerPixel;
 Color valCol;
 double height = hghBed5Height;
 double gScale = height/(gMax-gMin) /2.0 ;
 int start,end;
 char *chromName;
 float val, dirVal;
 int x1,x2;
 int y1;
 int w, h;
 
 double baseline = (float) height /2.0;
 
 char pixelStr[12];
 struct hash *pixelHashP = hashNew(0);
 struct hash *pixelHashN = hashNew(0);
 struct hmPixel *hm=NULL;
 
 struct hgStats *ibg=NULL;
 for(ibg = bg; ibg ; ibg = ibg->next)
     {
     chromName = ibg->chrom;
     start = ibg->chromStart;
     end = ibg->chromEnd;
 
     if (!hashLookup(chromHashX, chromName))
 	continue;
 
     int chromX= hashIntVal(chromHashX, chromName);
     int chromY= hashIntVal(chromHashY, chromName);
 
     x1 = pixelsPerBase*start + chromX;
     x2 = pixelsPerBase*end + chromX;
 
     w = x2-x1;
 
     dirVal = ibg->stats;  // statisitcs control drawing above or below baseline and color
     val = fabs(ibg->prob); // probability score control the absolute height of the drawing code
     if (val>gMax)
 	val =gMax;
     if (val<gMin)
 	val=gMin;
     
     if (dirVal >0)
 	y1 = baseline - val *gScale  + chromY+ yOff; //smaller value
     else
 	y1 = baseline + chromY + yOff; //smaller value
 
     h= val*gScale;
 
     safef(pixelStr,sizeof (pixelStr),"%d_%d",x1,x2);
     struct hash *pixelHash;
     if (dirVal>0)
 	pixelHash = pixelHashP;
     else
 	pixelHash = pixelHashN;
 
     struct hashEl *el = hashLookup(pixelHash, pixelStr);
     if (!el)
 	{
 	hm = AllocA(struct hmPixel);
 	hm->x = x1;
 	hm->y = y1;
 	hm->w = w;
 	hm->h = h;
 	hashAdd(pixelHash, pixelStr, hm);
 	}
     else
 	{
 	hm = el->val;
 	//TO DOS: the current implementation is taking the most significant value, a more sensible way to do it probably should be taking the average. Implement in the future.
 	if (hm->h <h)
 	    {
 	    hm->y = y1;
 	    hm->w = w;
 	    hm->h = h;
 	    }
 	}
     }
 
 int i;
 struct hash *ptHash[2];
 ptHash[0]= pixelHashP;
 ptHash[1]=pixelHashN;
 for (i=0; i<2; i++)
     {
     struct hashEl *elList = hashElListHash(ptHash[i]);
     struct hashEl *el;
     for (el = elList; el; el=el->next)
 	{
 	hm = el->val;
 	w = hm->w;
 	h= hm->h;
 	x1= hm->x;
 	y1= hm->y;
 
 	/* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	if ((w ==0) && (h != 0)) 
 	    w=1;
 
 	if (w<1 && h<1)
 	    continue;
 
 	if ( h <colorCutoff*gScale)
 	    valCol= MG_GRAY;
 	else if (i==0)
 	    valCol = MG_RED;
 	else 
 	    valCol = MG_GREEN;
 	
 	vgBox(vg, x1, y1, w, h, valCol);
 	}
     hashElFreeList(&elList);
     }
 hashFree(&pixelHashP);
 hashFree(&pixelHashN);
 }
 
 
 /* draw bed 4 hgHeatmap, in which the name field is the height of the heatmap*/
 void drawBedGraph4 (struct vGfx *vg, char* database, 
 		   struct genoLay *gl, char *tableName, int yOff,
 		   boolean leftLabel, boolean rightLabel, boolean firstInRow)
 {
 struct hashEl *el = hashLookup(ghHash, tableName);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", tableName);
 
 struct genoLayChrom *chrom=NULL;
 struct bed *bg=NULL, *ibg=NULL;
 float val;
 
 double pixelsPerBase = 1.0/gl->basesPerPixel;
 
 int x1,x2;
 int y1,y2;
 int w, h;
 int start,end;
 double gMin =  chromGraphMin(tableName);
 double gMax = chromGraphMax(tableName);
 double height = heatmapHeight(gh);
 double gScale = height/(gMax-gMin);
 struct rgbColor color = chromGraphColor(tableName);
 struct rgbColor black = {0,0,0} ;
 Color shadesOfColor[1];
 vgMakeColorGradient(vg, &black, &color, 1, shadesOfColor);
 Color valCol = shadesOfColor[0];
 int nField =4;
 
 /* Draw graphs on each chromosome */
 for(chrom = gl->chromList; chrom; chrom = chrom->next)
     {
     int chromX = chrom->x, chromY = chrom->y;
 
     bg = getBedGraph (database, tableName, chrom->fullName, nField);
     
     if (bg== NULL)
 	continue;
 
     vgSetClip(vg, chromX, chromY+yOff, chrom->width, height);
 
     /* Draw rest of points, connecting with line to previous point
      * if not too far off. */
     for(ibg = bg; ibg ; ibg = ibg->next)
 	{
        	start = ibg->chromStart;
 	end = ibg->chromEnd;
 	val = sqlFloat(ibg->name);
 
 	/* within a boundary */
 	if( val > gMax)
 	    val = gMax;
 	else if (val < gMin)
 	    val = gMin;
 
 	x1 = pixelsPerBase*start + chromX;
 	x2 = pixelsPerBase*end + chromX;
 	w = x2-x1;
  	if (val>0)
 	    {
 	    y1 = (height - (val - gMin)*gScale) + chromY+yOff; //smaller value
 	    y2 = (height - (gMin -gMin) *gScale) + chromY+yOff;//greater value
 	    h = y2-y1;
 	    
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0)) 
 		w=1;
 	    vgBox(vg,x1,y1, w, h,valCol);
 	    }
 	if (val<0)
 	    {
 	    y1 = (height - (val - gMax - gMin)*gScale) + chromY+yOff; //greater value
 	    y2 = (height - (gMax - gMax - gMin)*gScale) + chromY+yOff; //smaller value
 	    h = y1-y2;
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0))
 		w=1;
 	    vgBox(vg,x1,y2,w,h,valCol);
 	    }	
 	}
     vgUnclip(vg);
     bedFree(&bg);
     }
 return;
 }
 
 /* draw bed 5 in hgHeatmap, in which 
    the 4th (zero-based) field is the height of the segments
    the 5th (zero-based) field determines the color of the segments as VAL/10.0 (to give .1 accuracy)
  */
 void drawBedGraph5 (struct vGfx *vg, char* database, 
 		   struct genoLay *gl, char *tableName, int yOff,
 		   boolean leftLabel, boolean rightLabel, boolean firstInRow)
 {
 struct hashEl *el = hashLookup(ghHash, tableName);
 struct genoHeatmap *gh = NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", tableName);
 
 struct genoLayChrom *chrom=NULL;
 struct bed *bg=NULL, *ibg=NULL;
 float val, prob;
 
 double pixelsPerBase = 1.0/gl->basesPerPixel;
 
 int x1,x2;
 int y1,y2;
 int w, h;
 int start,end;
 double gMin =  chromGraphMin(tableName);
 double gMax = chromGraphMax(tableName);
 double height = heatmapHeight(gh);
 double gScale = height/(gMax-gMin);
 int nField =5;
 
 Color valCol;
 double md=10.0;
 double colorScale = COLOR_SCALE / md;
 Color shadesOfColor[EXPR_DATA_SHADES];
 struct rgbColor color = chromGraphColor(tableName);
 struct rgbColor black = {0,0,0};
 vgMakeColorGradient(vg, &black, &color, EXPR_DATA_SHADES, shadesOfColor);
 
 /* Draw graphs on each chromosome */
 for(chrom = gl->chromList; chrom; chrom = chrom->next)
     {
     int chromX = chrom->x, chromY = chrom->y;
 
     bg = getBedGraph (database, tableName, chrom->fullName, nField);
     
     if (bg== NULL)
 	continue;
 
     vgSetClip(vg, chromX, chromY+yOff, chrom->width, height);
 
     /* Draw rest of points, connecting with line to previous point
      * if not too far off. */
     for(ibg = bg; ibg ; ibg = ibg->next)
 	{
        	start = ibg->chromStart;
 	end = ibg->chromEnd;
 	val = sqlFloat(ibg->name);
 	prob = ibg->score/md;
 
 	/* within a boundary */
 	if( val > gMax)
 	    val = gMax;
 	else if (val < gMin)
 	    val = gMin;
 
 	x1 = pixelsPerBase*start + chromX;
 	x2 = pixelsPerBase*end + chromX;
 	w = x2-x1;
 
 	int colorIndex = abs(prob) * (EXPR_DATA_SHADES-1.0) * colorScale;	
 	if (colorIndex < 0) colorIndex = 0;
 	if (colorIndex >= EXPR_DATA_SHADES)
 	    colorIndex = EXPR_DATA_SHADES-1;
 	valCol = shadesOfColor[colorIndex];
 
  	if (val>0)
 	    {
 	    y1 = (height - (val - gMin)*gScale) + chromY+yOff; //smaller value
 	    y2 = (height - (gMin -gMin) *gScale) + chromY+yOff;//greater value
 	    h = y2-y1;
 	    
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0)) 
 		w=1;
 	    vgBox(vg,x1,y1, w, h,valCol);
 	    }
 	if (val<0)
 	    {
 	    y1 = (height - (val - gMax - gMin)*gScale) + chromY+yOff; //greater value
 	    y2 = (height - (gMax - gMax - gMin)*gScale) + chromY+yOff; //smaller value
 	    h = y1-y2;
 	    /* sometimes if the bed segment is too small, resulting in width=0, reset to 1 pixel length */
 	    if ((w ==0) && (h != 0))
 		w=1;
 	    vgBox(vg,x1,y2,w,h,valCol);
 	    }	
 	}
     vgUnclip(vg);
     bedFree(&bg);
     }
 return;
 }
 
 /* drawChromGraph in hgHeatmap */
 void drawChromGraphSimple (struct vGfx *vg, char* database, 
 			   struct genoLay *gl, char *tableName, int yOff,
 			   boolean leftLabel, boolean rightLabel, boolean firstInRow)
 {
 struct hashEl *el = hashLookup(ghHash, tableName);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", tableName);
 
 struct genoLayChrom *chrom=NULL;
 struct chromGraph *cg=NULL, *icg=NULL;
 double val;
 
 double pixelsPerBase = 1.0/gl->basesPerPixel;
 
 int x,lastX;
 int y,lastY;
 int start,lastStart;
 double gMin =  chromGraphMin(tableName);
 double gMax = chromGraphMax(tableName);
 double height = heatmapHeight(gh);
 double gScale = height/(gMax-gMin);
 int maxGapToFill = chromGraphMaxGapToFill(tableName);
 struct rgbColor color = chromGraphColor(tableName);
 Color shadesOfColor[1];
 struct rgbColor black = {0,0,0};
 vgMakeColorGradient(vg, &black, &color, 1, shadesOfColor);
 Color valCol = shadesOfColor[0];
 
 /* Draw graphs on each chromosome */
 for(chrom = gl->chromList; chrom; chrom = chrom->next)
     {
     int chromX = chrom->x, chromY = chrom->y;
 
     cg = getChromGraph (database, tableName, chrom->fullName);
     if (cg== NULL)
 	continue;
 
     val = cg->val;
 
     /* within a boundary */
     if(val > gMax)
 	val = gMax;
     else if (val < gMin)
 	val = gMin;
 
     start = lastStart = cg->chromStart;
     x = lastX = pixelsPerBase*start + chromX;
     y = lastY = (height - (val - gMin)*gScale) + chromY+yOff ;
 
     vgDot(vg, x, y, valCol);
     cg= cg->next;
 
     /* Draw rest of points, connecting with line to previous point
      * if not too far off. */
     for(icg = cg; icg!=NULL ; icg = icg->next)
 	{
        	start = icg->chromStart;
 	val = icg->val;
 
 	if( val > gMax)
 	    val = gMax;
 	else if (val < gMin)
 	    val = gMin;
 
 	x = pixelsPerBase*start + chromX;
 	y = (height - (val - gMin)*gScale) + chromY+yOff;
 
         if (x != lastX || y != lastY)
 	    {
 	    if (-(start - lastStart) <= maxGapToFill)
 		vgLine(vg, lastX, lastY, x, y, valCol);
 	    else
 		vgDot(vg, x, y, valCol);
 	    }
 	lastX = x;
 	lastY = y;
 	lastStart = start;
 	}
     chromGraphFree(&cg);
     }
 return;
 }
 
 void drawChromHeatmapsByPixel(struct vGfx *vg, char* database, 
 		       struct genoLay *gl, char *chromHeatmap, int yOff, 
 		       boolean leftLabel, boolean rightLabel, boolean firstInRow)
 /* Draw chromosome graph on all chromosomes in layout at given
  * y offset and height. */
 {
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 if (gh->accessTable)
     chromHeatmap = gh->accessTable;
 
 int *chromOrder = getBedOrder(gh);
 
 struct genoLayChrom *chrom=NULL;
 struct bed *ghBed=NULL, *nb=NULL;
 
 double pixelsPerBase = 1.0/gl->basesPerPixel;
 double md = maxDeviation(gh->name);
 double colorScale = COLOR_SCALE / md;
 double val;
 double absVal;
 int valId;
 Color valCol;
 int start, end;
 
 float gain = gh->gainFull;
  
 Color shadesOfUp[EXPR_DATA_SHADES];
 Color shadesOfDown[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 static struct rgbColor blue = {40, 150, 250};
 static struct rgbColor yellow = {220, 220, 0};
 if(cartUsualBoolean(cart, "hghDisplayBlueYellow", 0))
 {
     vgMakeColorGradient(vg, &black, &yellow, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg, &black, &blue, EXPR_DATA_SHADES, shadesOfDown);
 }else{
     vgMakeColorGradient(vg, &black, &red, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg, &black, &green, EXPR_DATA_SHADES, shadesOfDown);
 }
 
 char pixelStr[128];
 struct hash *pixelHash = hashNew(0);
 struct hmPixel *hm, *hmList = NULL;
 
 
 for(chrom = gl->chromList; chrom; chrom = chrom->next)
     {
     ghBed = getChromHeatmap(gh, chrom->fullName, TRUE);
     
     int chromX = chrom->x, chromY = chrom->y;
     
     vgSetClip(vg, chromX, chromY+yOff, chrom->width, heatmapHeight(gh));
     vgBox(vg, chromX, chromY+yOff , chrom->width, heatmapHeight(gh), MG_GRAY);
 
     for(nb = ghBed; nb; nb = nb->next)
 	{
 	start = nb->chromStart;
 	end = nb->chromEnd;
 
 	int i;
 	for(i = 0; i < nb->expCount; ++i)
 	    {
 	    val = nb->expScores[i];
 	    valId = nb->expIds[i];
 	    int orderId = chromOrder[valId];
 	    if (orderId == -1)
 		continue;
 
 	    absVal = fabs(val);
 
 	    int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
 
 	    /* Clip color index to fit inside of array, since we may have brightened it. */
             if (colorIndex < 0) colorIndex = 0;
             if (colorIndex >= EXPR_DATA_SHADES)
 	        colorIndex = EXPR_DATA_SHADES-1;
 
 	    if(val > 0)
 		valCol = shadesOfUp[colorIndex];
 	    else
 		valCol = shadesOfDown[colorIndex];
 
 	    int w = pixelsPerBase * (end - start) + 1;
 	    int h = experimentHeight();
 	    int x = pixelsPerBase * start + chromX;
 	    int y = chromY + yOff + orderId * h;
 
 	    safef(pixelStr, sizeof(pixelStr), "%d,%d", x, y);
 	    struct hashEl *el = hashLookup(pixelHash, pixelStr);
 	    if (!el)
 		{
 		hm = AllocA(struct hmPixel);
 		hm->x = x;
 		hm->y = y;
 		hm->w = w;
 		hm->h = h;
 		hm->val = 0.0;
 		hm->count = 0;
 		slAddHead(&hmList, hm);
 		hashAdd(pixelHash, pixelStr, hm);
 		}
 	    else
 		hm = el->val;
 	    
 	    hm->val += val;
 	    hm->count += 1;
 	    }
       	}
 
     for (hm = hmList; hm ; hm = hm->next)
 	{
 	val = hm->val / hm->count;
 
 	absVal = fabs(val) * gain;
 	
 	int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
 
 	/* Clip color index to fit inside of array, since we may have brightened it. */
 	if (colorIndex < 0) colorIndex = 0;
 	if (colorIndex >= EXPR_DATA_SHADES)
 	    colorIndex = EXPR_DATA_SHADES-1;
 
 	if(val > 0)
 	    valCol = shadesOfUp[colorIndex];
 	else
 	    valCol = shadesOfDown[colorIndex];
 
 	vgBox(vg, hm->x, hm->y, hm->w, hm->h, valCol); 
 	}
 
     freeHash(&pixelHash);
     pixelHash = hashNew(0);
     slFreeList(&hmList);
     hmList = NULL;
 
     bedFreeList(&ghBed);
     vgUnclip(vg);
     }
 }
 
 
 /*support funcion to build refGene common gene name identifier hash */
 struct hash *refGeneHash()
 {
 char query[128];
 safef(query, sizeof(query),"select name2 from refGene\n");
  
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr = sqlGetResult(conn, query);
 struct hash *refHash = hashNew(0);
 char **row=NULL;
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     char *name = *(row);
     hashAdd(refHash, name, "");
     }
 
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 return refHash;
 }
 
 struct hash *geneSetHash()
 {
 char query[128];
 safef(query, sizeof(query),"select name from genesets\n");
  
 struct sqlConnection *conn = hAllocConn("pathway");
 struct sqlResult *sr = sqlGetResult(conn, query);
 struct hash *refHash = hashNew(0);
 char **row=NULL;
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     char *name = *(row);
     hashAdd(refHash, name, "");
     }
 
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 return refHash;
 }
 
 
 /* Get the geneset that is defined by user */
 struct geneSet* getUserGeneSet()
 {
 struct geneSet *userGeneSet=NULL;
 char *varText = cartUsualString(cart, hghUserGeneList, "");
 struct slName *slList=NULL, *lineList=NULL, *fList =NULL;
 struct slName *sl, *sl1;
 if (isNotEmpty(varText) )
     {
     fList = slNameListFromStringTrimWhiteSpaces(varText,'\n');
     for (sl=fList; sl; sl=sl->next)
 	{
 	lineList = slNameListFromStringTrimWhiteSpaces(sl->name,',');
 	for (sl1 = lineList; sl1; sl1=sl1->next)
 	    {
 	    slNameAddHead(&slList, sl1->name);
 	    }
 	}
     slReverse(&slList);
     
     }
 else
     return NULL;
 
 struct slName *list;
 list = slList;
 if (list)
     {
     userGeneSet = AllocA(struct geneSet);
     userGeneSet->genes = list;
     userGeneSet->name = "User Defined";
     userGeneSet->displayName = "User Defined";
     userGeneSet->numGenes = slCount(list);
     userGeneSet->numGenesActive = 0;
     userGeneSet->x = 0;
     userGeneSet->y = 0;
     userGeneSet->width = 0;
     userGeneSet->pixelsPerGene = 0;
     }
 
 /* report genes in user defined set that does not match refGene identifier */
 struct hash *refHash = refGeneHash();
 if (userGeneSet)
     { 
     for (sl=userGeneSet->genes; sl ; sl=sl->next)
 	{
 	if (!hashFindVal(refHash,sl->name))
 	    hPrintf("%s: unrecognized gene name \n", sl->name);
 	}
     }
 return userGeneSet;
 }
 
 
 /* Get the pathways that is defined by user */
 struct geneSet* getUserGeneSetList()
 {
 char *varText = cartUsualString(cart, hghUserGeneSetList, "");
 struct slName *slList=NULL, *lineList=NULL, *fList =NULL;
 struct slName *sl, *sl1;
 
 struct hash *gSetHash = geneSetHash();
 if (isNotEmpty(varText) )
     {
     fList = slNameListFromStringTrimWhiteSpaces(varText,'\n');
     for (sl=fList; sl; sl=sl->next)
 	{
 	lineList = slNameListFromStringTrimWhiteSpaces(sl->name,',');
 	for (sl1 = lineList; sl1; sl1=sl1->next)
 	    {
 	    if (!hashFindVal(gSetHash, sl->name))
 		hPrintf("%s: unrecognized gene set name\n",sl->name);
 	    else
 		slNameAddHead(&slList, sl1->name);
 	    }
 	}
     slReverse(&slList);    
     }
 else
     return NULL;
 
 //slList is a list of pathway names
 struct geneSet *userGeneSet=NULL;
 struct geneSet *userGeneSetList=NULL;
 struct sqlConnection *conn = getPathwayDbConn();
 struct sqlResult *sr =NULL;
 for (sl=slList; sl; sl=sl->next)
     {
     //for each pathway, check db to see if we have the pathway, otherwise output error message
     char query[1024];
     safef(query, sizeof(query),"select members, displayName from genesets, pathwayname where genesets.name=\"%s\" and genesets.name=pathwayname.name;", sl->name);
 
     sr = sqlGetResult(conn, query);
 
     char **row = NULL;
     char *members =NULL;
     if ((row = sqlNextRow(sr)) != NULL)
 	{
 	members = cloneString(row[0]);
 	}
     else
 	hPrintf("%s: unrecognized pathway name \n", sl->name);
 
     struct slName *list =slNameListFromComma(members);
 
     //build the geneset
     userGeneSet = AllocA(struct geneSet);
     userGeneSet->genes = list;
     userGeneSet->name = sl->name;
     userGeneSet->displayName = cloneString(row[1]);
     userGeneSet->numGenes = slCount(list);
     userGeneSet->numGenesActive = 0;
     userGeneSet->x = 0;
     userGeneSet->y = 0;
     userGeneSet->width = 0;
     userGeneSet->pixelsPerGene = 0;
     //add to list
     slAddHead(&userGeneSetList,userGeneSet);
     sqlFreeResult(&sr);
     }
 slReverse(&userGeneSetList);
 hFreeConn(&conn);
 
 return userGeneSetList;
 }
 
 struct geneSet* getAllGeneSets()
 /* get all gene sets including user defined and the ones selected from the browser interface */
 {
 struct geneSet *userGeneSet = NULL;
 struct geneSet *userGeneSetList = NULL;
 struct geneSet *allGeneSets = NULL;
 
 /* user specific gene sets */
 userGeneSet = getUserGeneSet();
 userGeneSetList = getUserGeneSetList();
 if (userGeneSetList && userGeneSet)
     slAddHead(&userGeneSetList,userGeneSet);
 else if (userGeneSetList)
     userGeneSet = userGeneSetList;
 
 /* get system genesets */
 char *pathwayNames = getGeneSetMembers();
 
 if (pathwayNames)
     allGeneSets = getPathways(getPathwayDb(), pathwayNames);
 
 /* add user defined genesets */
 if (allGeneSets)
     {
     struct geneSet *start=allGeneSets;
     if (userGeneSet)
 	{
 	while (allGeneSets->next!= NULL)
 	    {
 	    allGeneSets = allGeneSets->next;
 	    }
 	allGeneSets->next=userGeneSet;
 	}
     allGeneSets = start;
     }
 else
     allGeneSets=  userGeneSet;
 
 /* test to see if selectedPathway is in user defined set or the selected gene set group */
 char *selectedPathway = cartUsualString(cart, hghSelectedPathway, NULL);
 if (selectedPathway)
     {
     struct geneSet* gs;
     for (gs=allGeneSets; gs; gs=gs->next)
 	{
 	if (sameWord(gs->name, selectedPathway))
 	    {
 	    gs->next=NULL;  // Todo: write a cloneGeneset function to duplicate gs and free memory of userGeneSet
 	    return gs;
 	    }
 	}
     }
 return allGeneSets;
 }
 
 void drawGeneSetHeatmapsByPixel(struct vGfx *vg, char* database, struct genoLay *gl, char *chromHeatmap, 
 				int yOff, struct geneSet *geneSets, struct hash *geneHash,
 				boolean leftLabel, boolean rightLabel, boolean firstInRow)
 /* Draw chromosome graph on all chromosomes in layout at given
  * y offset and height. */
 {
 if (!geneSets || !geneHash)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 int *chromOrder = getBedOrder(gh);
 struct bed *nb=NULL;
 
 float gain = gh->gainSet;
 double md = maxDeviation(chromHeatmap);
 double colorScale = COLOR_SCALE / md;
 double val;
 double absVal;
 int valId;
 Color valCol;
 Color shadesOfUp[EXPR_DATA_SHADES];
 Color shadesOfDown[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 static struct rgbColor blue = {40, 150, 250};
 static struct rgbColor yellow = {220, 220, 0};
 if(cartUsualBoolean(cart, "hghDisplayBlueYellow", 0))
 {
     vgMakeColorGradient(vg, &black, &yellow, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg, &black, &blue, EXPR_DATA_SHADES, shadesOfDown);
 }else{
     vgMakeColorGradient(vg, &black, &red, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg, &black, &green, EXPR_DATA_SHADES, shadesOfDown);
 }
 
 /* add geneHash specific layout */
 geneSetsAddPathwayLayout(geneSets, geneHash); 
 
 char pixelStr[128];
 struct hash *pixelHash = hashNew(0);
 struct hmPixel *hm, *hmList = NULL;
 
 struct geneSet *gs;
 for (gs = geneSets; gs ; gs = gs->next)
     {
     struct slName *sl;
     int gsX = gs->x, gsY = gs->y;
     int width = gs->width;
 
     vgSetClip(vg, gsX, gsY+yOff, width, heatmapHeight(gh));
     vgBox(vg, gsX, gsY+yOff , width, heatmapHeight(gh), MG_GRAY);
 
     double count = 0.0;
 
     struct slName *geneOrder = NULL;
     
     char method = getClusterMethod();
     char metric = getClusterMetric();
 
     if (doClustering())
 	geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);   //ordering inside gene set
 
     if (geneOrder == NULL)
 	geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
     for (sl = geneOrder; sl ; sl = sl->next)
 	{
 	struct hashEl *el = hashLookup(geneHash, sl->name);  //get the information from genesets
 	while (el)
 	    {
 	    nb = el->val;
 	  
 	    int x = (int) ( gs->pixelsPerGene * count + gsX );
 	    int w = ceil(gs->pixelsPerGene);
 	    int h = experimentHeight();
 		
 	    int i;
 	    for(i = 0; i < nb->expCount; ++i)
 		{
 		val = nb->expScores[i];
 		valId = nb->expIds[i];
 		int orderId = chromOrder[valId];
 		if (orderId == -1)
 		    continue;
 	      
 		int y = gsY + yOff + orderId * h;
 
 		safef(pixelStr, sizeof(pixelStr), "%d,%d", x, y);
 
 		struct hashEl *pixelEl = hashLookup(pixelHash, pixelStr);
 		if (!pixelEl)
 		    {
 		    hm = AllocA(struct hmPixel);
 		    hm->x = x;
 		    hm->y = y;
 		    hm->w = w;
 		    hm->h = h;
 		    hm->val = 0.0;
 		    hm->count = 0;
 		    slAddHead(&hmList, hm);
 		    hashAdd(pixelHash, pixelStr, hm);
 		    }
 		else
 		    hm = pixelEl->val;
 	    
 		hm->val += val;
 		hm->count += 1;
 		}
 	    count++;	  
 	    el = hashLookupNext(el);
 	    }
         }
 
 
     for (hm = hmList; hm ; hm = hm->next)
 	{
 	val = hm->val / (double) hm->count;
 	
 	if(val > 0)
 	    absVal = val;
 	else
 	    absVal = -val;
 
 	absVal = absVal *gain;
 	int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
 	/* Clip color index to fit inside of array, since we may have brightened it. */         
 	if (colorIndex < 0) colorIndex = 0;
 	if (colorIndex >= EXPR_DATA_SHADES)
 	    colorIndex = EXPR_DATA_SHADES-1;
 	
 	if(val > 0)
 	    valCol = shadesOfUp[colorIndex];
 	else
 	    valCol = shadesOfDown[colorIndex];
 	
 	vgBox(vg, hm->x, hm->y, hm->w, hm->h, valCol);
 	}
     
     vgUnclip(vg);
     
     freeHash(&pixelHash);
     slFreeList(&hmList);
     hmList = NULL;
     pixelHash = hashNew(0);
     }
 
 freeHash(&pixelHash);
 }                                                
 
 
 void drawGeneSetHeatmapsByPixelSNP(struct vGfx *vg, char* database, struct genoLay *gl, char *chromHeatmap, 
 				int yOff, struct geneSet *geneSets, struct hash *geneHash,
 				boolean leftLabel, boolean rightLabel, boolean firstInRow)
 /* Draw chromosome graph on all chromosomes in layout at given
  * y offset and height. */
 {
 if (!geneSets || !geneHash)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 int *chromOrder = getBedOrder(gh);
 struct bed *nb=NULL;
 
 float gain = gh->gainSet;
 double md = maxDeviation(chromHeatmap);
 double colorScale = COLOR_SCALE / md;
 double val;
 double absVal;
 int valId;
 Color valCol;
 
 Color white = vgFindColorIx(vg, 255, 255, 255);
 Color shadesOfRed[EXPR_DATA_SHADES];
 
 Color shadesOfGreen[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 vgMakeColorGradient(vg, &black, &red, EXPR_DATA_SHADES, shadesOfRed);
 vgMakeColorGradient(vg, &black, &green, EXPR_DATA_SHADES, shadesOfGreen); 
 
 /* add geneHash specific layout */
 geneSetsAddPathwayLayout(geneSets, geneHash); 
 
 //vgBox(vg, gsX, gsY+yOff , width, heatmapHeight(gh), MG_GRAY);
 
 char pixelStr[128];
 struct hash *pixelHash = hashNew(0);
 struct hmPixel *hm, *hmList = NULL;
 
 struct geneSet *gs;
 for (gs = geneSets; gs ; gs = gs->next)
     {
     struct slName *sl;
     int gsX = gs->x, gsY = gs->y;
     int width = gs->width;
 
 //    vgSetClip(vg, gsX, gsY+yOff, width + 1, heatmapHeight(gh));
     vgBox(vg, gsX-1, gsY+yOff-1 , width + 2, heatmapHeight(gh)+2, MG_GRAY);
     vgSetClip(vg, gsX, gsY+yOff, width, heatmapHeight(gh));
     double count = 0.0;
 
     struct slName *geneOrder = NULL;
     
     char method = getClusterMethod();
     char metric = getClusterMetric();
 
     if (doClustering())
 	geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);   //ordering inside gene set
 
     if (geneOrder == NULL)
 	geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
     for (sl = geneOrder; sl ; sl = sl->next)
 	{
 	struct hashEl *el = hashLookup(geneHash, sl->name);  //get the information from genesets
 	while (el)
 	    {
 	    nb = el->val;
 	  
 	    int x = (int) ( gs->pixelsPerGene * count + gsX );
 	    int w = ceil(gs->pixelsPerGene);
 	    int h = experimentHeight();
 		
 	    int i;
 	    for(i = 0; i < nb->expCount; ++i)
 		{
 		val = nb->expScores[i];
 		valId = nb->expIds[i];
 		int orderId = chromOrder[valId];
 		if (orderId == -1)
 		    continue;
 	      
 		int y = gsY + yOff + orderId * h;
 
 		safef(pixelStr, sizeof(pixelStr), "%d,%d", x, y);
 
 		struct hashEl *pixelEl = hashLookup(pixelHash, pixelStr);
 		if (!pixelEl)
 		    {
 		    hm = AllocA(struct hmPixel);
 		    hm->x = x;
 		    hm->y = y;
 		    hm->w = w;
 		    hm->h = h;
 		    hm->val = 0.0;
 		    hm->count = 0;
 		    slAddHead(&hmList, hm);
 		    hashAdd(pixelHash, pixelStr, hm);
 		    }
 		else
 		    hm = pixelEl->val;
 	    
 		hm->val += val;
 		hm->count += 1;
 		}
 	    count++;	  
 	    el = hashLookupNext(el);
 	    }
         }
 
 
     for (hm = hmList; hm ; hm = hm->next)
 	{
 	val = hm->val; // / (double) hm->count;
 	val = round(val);
 
 	if(val > 0)
 	    absVal = val;
 	else
 	    absVal = -val;
 
 	absVal = absVal *gain;
 	int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
 	/* Clip color index to fit inside of array, since we may have brightened it. */         
 	if (colorIndex < 0) colorIndex = 0;
 	if (colorIndex >= EXPR_DATA_SHADES)
 	    colorIndex = EXPR_DATA_SHADES-1;
 	
 	if (val == 0.0)
 	    valCol = white;
 	else if (val > 0.0)
 	    valCol = shadesOfRed[colorIndex];
 	else
 	    valCol = shadesOfGreen[colorIndex];
 	
 	vgBox(vg, hm->x, hm->y, hm->w, hm->h, valCol);
 	}
     
     vgUnclip(vg);
     
     freeHash(&pixelHash);
     slFreeList(&hmList);
     hmList = NULL;
     pixelHash = hashNew(0);
     }
 
 freeHash(&pixelHash);
 }                                                
        
 void drawGeneSetHeatmapByPixel(struct hvGfx *vg, char* database, struct genoLay *gl, 
 			       struct geneSet *gs, struct hash *geneHash,
 			       char *chromHeatmap, int yOff, 
 			       boolean leftLabel, boolean rightLabel, boolean firstInRow)
 /* Draw chromosome graph on all chromosomes in layout at given
  * y offset and height. */
 {
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 int *chromOrder = getBedOrder(gh);
 struct genoLayChrom *chrom=NULL;
 struct bed *nb=NULL;
 
 float gain = gh->gainSet;
 
 double md = maxDeviation(chromHeatmap);
 double colorScale = COLOR_SCALE / md;
 double val;
 double absVal;
 int valId;
 Color valCol;
 
 Color shadesOfUp[EXPR_DATA_SHADES];
 Color shadesOfDown[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 static struct rgbColor blue = {40, 150, 250};
 static struct rgbColor yellow = {220, 220, 0};
 
 if(cartUsualBoolean(cart, "hghDisplayBlueYellow", 0))
 {
     vgMakeColorGradient(vg->vg, &black, &yellow, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg->vg, &black, &blue, EXPR_DATA_SHADES, shadesOfDown);
 }
 else
 {
     vgMakeColorGradient(vg->vg, &black, &red, EXPR_DATA_SHADES, shadesOfUp);
     vgMakeColorGradient(vg->vg, &black, &green, EXPR_DATA_SHADES, shadesOfDown);
 }
 
 
 chrom = gl->chromList;
 
 char pixelStr[128];
 struct hash *pixelHash = hashNew(0);
 struct hmPixel *hm, *hmList = NULL;
 
 struct slName *sl;
 
 int gsX = gs->x, gsY = gs->y;
 int width = gs->width;
 
 vgSetClip(vg->vg, gsX, gsY+yOff, width, heatmapHeight(gh));
 vgBox(vg->vg, gsX, gsY+yOff , width, heatmapHeight(gh), MG_GRAY);
     
 double count = 0.0;
 
 struct slName *geneOrder = NULL;
 
 char method = getClusterMethod();
 char metric = getClusterMetric();
 
 if (doClustering())
     geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);
 
 if (geneOrder == NULL)
     geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
 for (sl = geneOrder; sl ; sl = sl->next)
     {
     struct hashEl *el = hashLookup(geneHash, sl->name);
 
     while (el)
 	{
 	nb = el->val;
     
 	int x = (int) ( gs->pixelsPerGene * count + gsX );
 	int i;
 
 	for(i = 0; i < nb->expCount; ++i)
 	    {
 	    val = nb->expScores[i];
 	    valId = nb->expIds[i];
 	    int orderId = chromOrder[valId];
 	    if (orderId == -1)
 		continue;
 	    
 	    int w = ceil(gs->pixelsPerGene);
 	    int h = experimentHeight();
 	    int y = gsY + yOff + orderId * h;
 	
 	    safef(pixelStr, sizeof(pixelStr), "%d,%d", x, y);
 	    struct hashEl *pixelEl = hashLookup(pixelHash, pixelStr);
 	    if (!pixelEl)
 		{
 		hm = AllocA(struct hmPixel);
 		hm->x = x;
 		hm->y = y;
 		hm->w = w;
 		hm->h = h;
 		hm->val = 0.0;
 		hm->count = 0;
 		slAddHead(&hmList, hm);
 		hashAdd(pixelHash, pixelStr, hm);
 		}
 	    else
 		hm = pixelEl->val;
 	    
 	    hm->val += val;
 	    hm->count += 1;
 	    }
 	count++;
 	el = hashLookupNext(el);
 	}
     }
 
 for (hm = hmList; hm ; hm = hm->next)
     {
     val = hm->val / (double) hm->count;
     
     absVal = fabs(val) *gain;
     
     int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
     /* Clip color index to fit inside of array, since we may have brightened it. */         
     if (colorIndex < 0) colorIndex = 0;
     if (colorIndex >= EXPR_DATA_SHADES)
 	colorIndex = EXPR_DATA_SHADES-1;
     
     if(val > 0)
 	valCol = shadesOfUp[colorIndex];
     else
 	valCol = shadesOfDown[colorIndex];
     
     vgBox(vg->vg, hm->x, hm->y, hm->w, hm->h, valCol);
     }
 
 vgUnclip(vg->vg);
 
 drawGeneSetLabel(gl, gs, vg, MG_BLACK,FALSE);
 drawGeneSetBand(gl, gs, vg, MG_BLACK);
 
 freeHash(&pixelHash);
 slFreeList(&hmList);
 }
 
 
 void drawGeneSetHeatmapByPixelSNP(struct hvGfx *vg, char* database, struct genoLay *gl, 
 			       struct geneSet *gs, struct hash *geneHash,
 			       char *chromHeatmap, int yOff, 
 			       boolean leftLabel, boolean rightLabel, boolean firstInRow)
 /* Draw chromosome graph on all chromosomes in layout at given
  * y offset and height. */
 {
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 int *chromOrder = getBedOrder(gh);
 struct genoLayChrom *chrom=NULL;
 struct bed *nb=NULL;
 
 float gain = gh->gainSet;
 
 double md = maxDeviation(chromHeatmap);
 double colorScale = COLOR_SCALE / md;
 double val;
 double absVal;
 int valId;
 Color valCol;
 
 Color white = vgFindColorIx(vg->vg, 255, 255, 255);
 Color shadesOfRed[EXPR_DATA_SHADES];
 Color shadesOfGreen[EXPR_DATA_SHADES];
 
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 
 vgMakeColorGradient(vg->vg, &black, &red, EXPR_DATA_SHADES, shadesOfRed);
 vgMakeColorGradient(vg->vg, &black, &green, EXPR_DATA_SHADES, shadesOfGreen); 
 
 chrom = gl->chromList;
 
 char pixelStr[128];
 struct hash *pixelHash = hashNew(0);
 struct hmPixel *hm, *hmList = NULL;
 
 struct slName *sl;
 
 int gsX = gs->x, gsY = gs->y;
 int width = gs->width;
 
 vgSetClip(vg->vg, gsX, gsY+yOff, width, heatmapHeight(gh));
 //vgBox(vg->vg, gsX, gsY+yOff , width, heatmapHeight(gh), MG_GRAY);
     
 double count = 0.0;
 
 struct slName *geneOrder = NULL;
 
 char method = getClusterMethod();
 char metric = getClusterMetric();
 
 if (doClustering())
     geneOrder = clusterGeneSet(geneHash, gs->genes, method, metric);
 
 if (geneOrder == NULL)
     geneOrder = gs->genes;  // Make sure we display something if clustering failed.
 
 for (sl = geneOrder; sl ; sl = sl->next)
     {
     struct hashEl *el = hashLookup(geneHash, sl->name);
 
     while (el)
 	{
 	nb = el->val;
     
 	int x = (int) ( gs->pixelsPerGene * count + gsX );
 	int i;
 
 	for(i = 0; i < nb->expCount; ++i)
 	    {
 	    val = nb->expScores[i];
 	    valId = nb->expIds[i];
 	    int orderId = chromOrder[valId];
 	    if (orderId == -1)
 		continue;
 	    
 	    int w = ceil(gs->pixelsPerGene);
 	    int h = experimentHeight();
 	    int y = gsY + yOff + orderId * h;
 	
 	    safef(pixelStr, sizeof(pixelStr), "%d,%d", x, y);
 	    struct hashEl *pixelEl = hashLookup(pixelHash, pixelStr);
 	    if (!pixelEl)
 		{
 		hm = AllocA(struct hmPixel);
 		hm->x = x;
 		hm->y = y;
 		hm->w = w;
 		hm->h = h;
 		hm->val = 0.0;
 		hm->count = 0;
 		slAddHead(&hmList, hm);
 		hashAdd(pixelHash, pixelStr, hm);
 		}
 	    else
 		hm = pixelEl->val;
 	    
 	    hm->val += val;
 	    hm->count += 1;
 	    }
 	count++;
 	el = hashLookupNext(el);
 	}
     }
 
 for (hm = hmList; hm ; hm = hm->next)
     {
     val = hm->val; // / (double) hm->count;
     
     absVal = fabs(val) *gain;
     
     int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
     /* Clip color index to fit inside of array, since we may have brightened it. */         
     if (colorIndex < 0) colorIndex = 0;
     if (colorIndex >= EXPR_DATA_SHADES)
 	colorIndex = EXPR_DATA_SHADES-1;
 
     if (val == 0.0)
 	valCol = white;
     else if (val > 0.0)
 	valCol = shadesOfRed[colorIndex];
     else
 	valCol = shadesOfGreen[colorIndex];
 
     vgBox(vg->vg, hm->x, hm->y, hm->w, hm->h, valCol);
     }
 
 vgUnclip(vg->vg);
 
 drawGeneSetLabel(gl, gs, vg, MG_BLACK,FALSE);
 drawGeneSetBand(gl, gs, vg, MG_BLACK);
 
 freeHash(&pixelHash);
 slFreeList(&hmList);
 }
 
 
 char *getId(struct sqlConnection *conn, char *table, char *key, char *sample, char *value)
 /* get patient ID from sample (or experiment) Id */
 {
 char query[512];
 safef(query, sizeof(query), "select %s from %s where %s = '%s' ", key, table, value, sample);
 return sqlQuickString(conn, query);
 }
 
 struct featureColor* getFeatureColorInCol(struct sqlConnection *conn, struct vGfx *vg, 
 					  struct genoHeatmap *gh, struct column *col)
 {
 if (gh == NULL || conn == NULL || col == NULL)
     return NULL;
 
 char *labTable = gh->patTable;
 char *value = gh->sampleField;
 char *key = gh->patField; 
 
 double colorScale = 0.0;
 double val;
 double absVal,  minVal, maxVal;
 char *minCutVal, *maxCutVal;
 
 Color valCol;
 Color shadesOfRed[EXPR_DATA_SHADES];
 Color shadesOfGreen[EXPR_DATA_SHADES];
 Color shadesOfYellow[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 static struct rgbColor yellow = {255, 255, 0};
 vgMakeColorGradient(vg, &black, &red, EXPR_DATA_SHADES, shadesOfRed);
 vgMakeColorGradient(vg, &black, &green, EXPR_DATA_SHADES, shadesOfGreen);
 vgMakeColorGradient(vg, &black, &yellow, EXPR_DATA_SHADES, shadesOfYellow);
 
 minVal = atof(col->cellMinVal(col, conn)) ;
 maxVal = atof(col->cellMaxVal(col, conn)) ;
 
 minCutVal = col->cellMinCutVal(col, conn);
 maxCutVal = col->cellMaxCutVal(col, conn);
 
 /* double color: consistant with the scale of microarray data display */
 if ((minVal<0) && (maxVal>0))
     {
     double md = max(abs(minVal), maxVal);
     colorScale = COLOR_SCALE  / md;
     }
 /* single color */
 else
     colorScale = COLOR_SCALE / (maxVal - minVal);
 
 int i;
 struct slName *sl = NULL;
 struct featureColor *fcList = NULL;
 
 for (sl = gh->sampleList; sl; sl = sl->next)
     {
     int orderId = hashIntValDefault(gh->sampleOrder, sl->name, -1);
     if (orderId == -1)
 	continue;
     
     int index = -1;
     for (i = 0; i < gh->expCount; i++)
 	{
 	if (gh->expIdOrder[i] == orderId)
 	    {
 	    index = i;
 	    break;
 	    }
 	}
 
     struct slName *id = slNameNew(getId(conn, labTable, key, sl->name, value));
 
     char *cellVal = col->cellVal(col, id, conn);
     valCol = MG_GRAY;
     if (cellVal)
 	{
 	val = atof(cellVal);
 	if (minCutVal)
 	    {
 	    if (val < atof(minCutVal))
 		continue;
 	    }
 	if (maxCutVal)
 	    {
 	    if (val > atof(maxCutVal))
 		continue;
 	    }
 	absVal = fabs(val);
 
 	int colorIndex = (int)(absVal * (EXPR_DATA_SHADES-1.0) * colorScale);
 
         /* Clip color index to fit inside of array, since we may have brightened it. */
 	if (colorIndex < 0) colorIndex = 0;
 	if (colorIndex >= EXPR_DATA_SHADES)
 	    colorIndex = EXPR_DATA_SHADES-1;
 	if(val < 0.0)
 	    valCol = shadesOfYellow[colorIndex];
 	else
 	    valCol = shadesOfGreen[colorIndex];
 	}
 
     struct featureColor *fc = AllocA(struct featureColor);
     fc->name = cloneString(fc->name);
     fc->id = cloneString(id->name);
     fc->index = index;
     fc->order = orderId;
     fc->color = valCol;
 
     slAddHead(&fcList, fc);
     freez(&id);                                                                           
     }
 
 return fcList;
 }
 
 
 void drawPCAPlot(struct vGfx *vg, char *database, struct geneSet *gs, 
 		 struct hash *geneHash, char *chromHeatmap, int yOff)
 {
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap); 
 
 char *raName = gh->raFile;
 struct sqlConnection *conn = getFeatureDbConn(gh);
 struct column *col, *colList = getColumns(conn, raName,gh->patDb);
 struct featureColor *fcList = NULL;
 for (col = colList; col != NULL; col = col->next)
     {
     if (col->on)
 	{
 	fcList = getFeatureColorInCol(conn, vg, gh, col);  
 	break;
 	}
     }
 
 performPCAandPlot(vg, gs->width, heatmapHeight(gh), 0, yOff, 
 		  geneHash, gs->genes, fcList);
 
 hFreeConn(&conn);
 slFreeList(&fcList);
 }                                                
        
 
 void drawFeatureLabel(char *chromHeatmap, struct genoLay *fs, struct vGfx *vg, int color)
 /* Draw feature labels in image */
 {
 if (!fs)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 char *raName = gh->raFile;
 struct sqlConnection *conn = getFeatureDbConn(gh);
 struct column *col, *colList = getColumns(conn, raName,gh->patDb);
 
 double pixelsPerBase = fs->pixelsPerBase;
 
 struct genoLayChrom *chrom= fs->chromList;
 
 int chromX = chrom->x, chromY = chrom->y;
 
 int start = 0;
 for (col = colList; col != NULL; col = col->next)
     {
     if (col->on)
 	{
 	int x = pixelsPerBase * start + chromX;
 	int w = pixelsPerBase;
 	int y = chromY;
 	verticalTextCentered(vg, x, y, w, hghFeatureLabel, color, fs->font, col->shortLabel);
 	start++;
 	}
     }
 hFreeConn(&conn);
 }
 
 void drawFeatures(struct vGfx *vg, char *chromHeatmap, struct genoLay *fs, int yOff, boolean reverse)
 /* Draw features to right of chromosomes in layout at given
  * y offset and height. */
 {
 if (!fs)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 /* set up connection to table with both patient and sample information */
 char *labTable = gh->patTable;
 char *value = gh->sampleField;
 char *key = gh->patField;
 char *db = gh->patDb;
 
 if ((labTable == NULL) || (key == NULL) || (value == NULL) || (db==NULL))
     return;
 
 struct sqlConnection *conn = hAllocConn(db);
 
 if (!conn)
     return;
 
 struct genoLayChrom *chrom=NULL;
     
 double pixelsPerBase = fs->pixelsPerBase;
 double colorScale = 0.0; 
 double val;
 double absVal,  minVal, maxVal;
 char *minCutVal, *maxCutVal;
 double offset;
 int reverseColor;
 
 int start = 0;
 Color valCol;
 Color shadesOfRed[EXPR_DATA_SHADES];
 Color shadesOfGreen[EXPR_DATA_SHADES];
 Color shadesOfYellow[EXPR_DATA_SHADES];
 static struct rgbColor black = {0, 0, 0};
 static struct rgbColor red = {255, 0, 0};
 static struct rgbColor green = {0, 255, 0};
 static struct rgbColor yellow = {255, 255, 0};
 vgMakeColorGradient(vg, &black, &red, EXPR_DATA_SHADES, shadesOfRed);
 vgMakeColorGradient(vg, &black, &green, EXPR_DATA_SHADES, shadesOfGreen);
 vgMakeColorGradient(vg, &black, &yellow, EXPR_DATA_SHADES, shadesOfYellow);
 
 struct slName *id = NULL;
 char *raName = gh->raFile;
 struct column *col, *colList = getColumns(conn, raName, gh->patDb);
 
 for(chrom = fs->chromList; chrom; chrom = chrom->next)
     {    
     int chromX = chrom->x, chromY = chrom->y;
     
     vgSetClip(vg, chromX, chromY+yOff, chrom->width, chrom->height);
     vgBox(vg, chromX, chromY+yOff , chrom->width, chrom->height, MG_WHITE);
     
     start = 0;
     for (col = colList; col != NULL; col = col->next)
 	{
         if (col->on)
 	    {
 	    offset = atof(col->cellOffsetVal(col));
 	    reverseColor = atoi(col->cellColorReverseVal(col));
 
 	    if (reverseColor == -1)
 		{
 		maxVal = reverseColor*(atof(col->cellMinVal(col, conn)) + offset);
 		minVal = reverseColor*(atof(col->cellMaxVal(col, conn)) + offset);
 		}
 	    else
 		{
 		minVal = atof(col->cellMinVal(col, conn)) + offset;
 		maxVal = atof(col->cellMaxVal(col, conn)) + offset;	    
 		}
 
 	    minCutVal = col->cellMinCutVal(col, conn);
 	    maxCutVal = col->cellMaxCutVal(col, conn);
 
 
 	    /* double color: consistant with the scale of microarray data display */
 	    if ((minVal<0) && (maxVal>0))
 		{
 		double md = max(fabs(minVal), maxVal) ;
 		colorScale = COLOR_SCALE  / md;
 		}
 	    /* single color */
 	    else
 		colorScale = COLOR_SCALE / (maxVal - minVal);
 
 	    struct slName *sl = NULL;
 	    for (sl = gh->sampleList; sl ; sl = sl->next)
 		{
 		int orderId = hashIntValDefault(gh->sampleOrder, sl->name, -1);
 
 		if (orderId == -1) 
 		    continue;
                 
 		id = slNameNew(getId(conn, labTable, key, sl->name, value));
 
 		char *cellVal = col->cellVal(col, id, conn);
 	        valCol = MG_GRAY;            
 		if (cellVal)
 		    {
 		    val = atof(cellVal) ;
 		    if (minCutVal)
 			{
 			if (val < atof(minCutVal))
 			    continue;
 			}
 		    if (maxCutVal)
 			{
 			if (val> atof(maxCutVal))
 			    continue;
 			}
 		    absVal = fabs(val);
 		    absVal = reverseColor *( absVal +offset);
 
 		    /* double color: consistant with the scale of microarray data display */
 		    int colorIndex ;
 		    if ((minVal<0) && (maxVal>0))
 			colorIndex = (int)((absVal) * (EXPR_DATA_SHADES-1.0) * colorScale);
 		    else
 			colorIndex = (int)((absVal-minVal) * (EXPR_DATA_SHADES-1.0) * colorScale);
 
 		    /* Clip color index to fit inside of array, since we may have brightened it. */
 		    if (colorIndex < 0) colorIndex = 0;
 		    if (colorIndex >= EXPR_DATA_SHADES)
 			colorIndex = EXPR_DATA_SHADES-1;
 		    
 		    if (!reverse)
 			{
 			if(val >= 0.0)
 			    valCol = shadesOfYellow[colorIndex];
 			else
 			    valCol = shadesOfGreen[colorIndex];
 			}
 		    else
 			{
 			if(val <= 0.0)
 			    valCol = shadesOfYellow[colorIndex];
 			else
 			    valCol = shadesOfGreen[colorIndex];
 			}
 		    }
                 
         	int w = pixelsPerBase;
         	int h = experimentHeight();
         	int x = pixelsPerBase * start + chromX;
         	int y = chromY + yOff + orderId * h;
 		
         	vgBox(vg, x, y, w, h, valCol);
 		freez(&id);
 		}
 	    start++;
 	    }
 	}
     vgUnclip(vg);
     }
 
 hFreeConn(&conn);
 }
 
 
 void drawSubgroups(struct vGfx *vg, char *chromHeatmap, 
 		   struct genoLay *fs, int yOff)
 /* Draw features to right of chromosomes in layout at given
  * y offset and height. */
 {
 if (!fs)
     return;
 
 struct hashEl *el = hashLookup(ghHash, chromHeatmap);
 struct genoHeatmap *gh =NULL;
 if (el)
     gh = el->val;
 else
     errAbort("no heatmap %s\n", chromHeatmap);
 
 char *raName = gh->raFile;
 int subsetNum = cartUsualInt(cart, hghSubgroupNum, hghSubgroupDefaultNum);
 
 /* This is the key function to call for subgrouping */
 struct slName **ptSubsets = getSubsets(gh, subsetNum, raName );
 if (!ptSubsets)
     return;
 int i;
 for (i=0; i< subsetNum; i++)
     if (!ptSubsets[i])
 	return;
 
 int subset =0;
 Color valCol;
 struct genoLayChrom *chrom;
 char *sample;
 
 for(chrom = fs->chromList; chrom  ; chrom = chrom->next,subset++)
     {    
     
     struct slName *subSampleList  = ptSubsets[subset];
 
     int chromX = chrom->x, chromY = chrom->y;
     
     vgSetClip(vg, chromX, chromY+yOff, chrom->width, chrom->height);
     vgBox(vg, chromX, chromY+yOff , chrom->width, chrom->height, MG_WHITE);
     
     struct slName *sl = NULL;
     for (sl = gh->sampleList; sl ; sl = sl->next)
 	{
 	sample = sl->name;
 
 	int orderId = hashIntValDefault(gh->sampleOrder, sample, -1);
 	
 	if (orderId == -1) 
 	    continue;
                 
 
 	if (slNameInList( subSampleList, sample))
 	    valCol = advFilterColor (subset);
 	else
 	    continue;
 
 	int w = chrom->width;
 	int h = experimentHeight();
 	int x = chromX;
 	int y = chromY + yOff + orderId * h;
 
 	vgBox(vg, x, y, w, h, valCol);	
 	}
     }
 
 for (subset=0; subset < subsetNum; subset++)
     slNameFreeList(ptSubsets[subset]);
 free(ptSubsets);
 
 vgUnclip(vg);
 }
 
 
 void genomeGif(struct sqlConnection *conn, struct genoLay *gl,
 	       char *psOutput)
 /* Create genome GIF file and HT that includes it. */
 {
 struct hvGfx *vg;
 struct tempName gifTn;
 Color shadesOfGray[10];
 int maxShade = ArraySize(shadesOfGray)-1;
 
 int drawChroms = sameString(displayType(), "chromosome");
 
 /*TODO: change code to use a better genoLay strategy */
 int totalW = selectedHeatmapWidth();
 int totalH = selectedHeatmapHeight(gl);
 
 if (psOutput)
     {
     vg = hvGfxOpenPostScript(totalW, totalH, psOutput);
     }
 else
     {
     /* Create gif file and make reference to it in html. */
     trashDirFile(&gifTn, "hgh", "ideo", ".gif");
-    vg = hvGfxOpenGif(totalW, totalH, gifTn.forCgi);
+    vg = hvGfxOpenGif(totalW, totalH, gifTn.forCgi, FALSE);
     
     hPrintf("<INPUT TYPE=IMAGE SRC=\"%s\" BORDER=1 WIDTH=%d HEIGHT=%d NAME=\"%s\">",
 	    gifTn.forHtml, totalW, totalH, hghClick);
     }
 
 struct genoHeatmap *gh= NULL;
 struct slRef *ref= NULL;
 char *db, *tableName=NULL;
 float colorCutoff = hghProbCutoff;
 
 geneSetsChromLayout (allGeneSets);    // consider rewriting to reset gl ,and remove layout info from genesets
 
 int totalYOff = 0;
 int offset=0;
 
 for (ref = ghList; ref != NULL; ref = ref->next)
     {
     boolean notDraw = FALSE;
     gh= ref->val;
 
     db = gh->database;
     tableName = gh->name;
     
     if (!drawChroms && differentWord(gh->dataType,"bed 15"))
 	continue;
 
     /* Draw dataset label */
     totalYOff += hghBetweenRowPad; 
 
     struct trackLayout tl;  /* Dimensions of things, fonts, etc. */
     trackLayoutInit(&tl, cart);
     int labelPad =tl.fontHeight+10;
     hvGfxTextCentered(vg,0,totalYOff,gl->picWidth, labelPad, MG_BLACK,gl->font,gh->shortLabel);
     totalYOff += labelPad; 
 
     /* draw heatmap */
     if (drawChroms)
 	{
 	offset = totalYOff;
 	if (sameWord(gh->dataType,"bed 15"))
 	    drawChromHeatmapsByPixel(vg->vg, db, gl, tableName, 
 				     offset , TRUE, TRUE, TRUE);
 	else if (sameWord(gh->dataType,"bed 4"))
 	    drawBedGraph4 (vg->vg, db, gl, tableName, 
 			   offset,  TRUE, TRUE, TRUE);
 	else if (sameWord(gh->dataType,"bed 5"))
 	    drawBedGraph5 (vg->vg, db, gl, tableName, 
 			   offset,  TRUE, TRUE, TRUE);
 	else if (sameWord(gh->dataType,"chromGraph"))
 	    drawChromGraphSimple (vg->vg, db, gl, tableName, 
 				  offset,  TRUE, TRUE, TRUE);	    
 	else
 	    notDraw = TRUE;
 
 	/* draw the analysis results */
 	if (gh->anaResult)
 	    {
 	    offset += heatmapHeight(gh)+hghBetweenRowPad;  
 	    drawHgStats (vg->vg, gh->anaResult->stats, gl, offset,
 			 0,  gh->anaResult->max, colorCutoff);
 	    }
 	}
     else
 	{
 	struct hash *geneHash = NULL;
 	getChromHeatmapHash(&geneHash, db, gh->probeTable,
 			    tableName, NULL, allGeneSets);
 
 	offset = totalYOff;
 	if (sameWord(gh->platform, "SNP"))
 	    drawGeneSetHeatmapsByPixelSNP(vg->vg, db, gl, tableName, offset, 
 				       allGeneSets, geneHash, TRUE, TRUE, TRUE);
 	else
 	    drawGeneSetHeatmapsByPixel(vg->vg, db, gl, tableName, offset, 
 				       allGeneSets, geneHash, TRUE, TRUE, TRUE);
 
 	/* draw gene labels if there is enough horizontal space*/
 	if (sameWord(gh->dataType,"bed 15"))
 	    {
 	    offset += heatmapHeight(gh);
 	    if (ifDrawGeneLabels())
 		{
 		drawGeneLabels(vg->vg, gl, tableName,allGeneSets, geneHash, offset);
 		offset += hghGeneLabelHeight;
 		}
 	    }
 
 	/* draw analysis results */
 	int isBlockStat = cartUsualBoolean(cart, hghPerformBlockStats, 0);
 	if (gh->anaResultHash)
 	    {
 	    offset += hghBetweenRowPad;
 	    drawGeneSetHgStats(vg->vg, gh->anaResultHash->hash, gl, offset,
 			       allGeneSets, 0, 3, colorCutoff, isBlockStat, tableName, geneHash);	
 	    }
 	freeHash(&geneHash);
 	}
     
     /* generate a new gl that is only for the panel of the heatmap */
     struct genoLay *newGl=AllocA(struct genoLay);
     newGl->picWidth = gl->picWidth;
     newGl->picHeight = heatmapHeight(gh);
     newGl->font = gl->font;
     struct genoLayChrom *newChrom = AllocA(struct genoLayChrom);
     struct genoLayChrom *chrom = gl->chromList;
     newChrom->next = NULL;
     newChrom->y = totalYOff;
     newChrom->x = chrom->x;
     newChrom->width = gl->picWidth;
     newChrom->height = heatmapHeight(gh);
     newGl->chromList = newChrom;
 
     /* GenoLay area for subgroup labeling */
     struct genoLay *subGl = subgroupLayout (gh,newGl);
     if (!subGl)
 	subGl = defaultLayoutH (newGl, 0, 0);
 
     /* draw subgroup color lable */
     if (gotAdvFilter(gh->patDb))
 	drawSubgroups(vg->vg, tableName, subGl, 0);
 
 
     /* GenoLay area for feature sorter */
     struct genoLay *fs = featureLayout(gh, subGl);
     if (!fs)
 	fs = defaultLayoutH (subGl, 0, 0);
 
     /* draw feature sorter */
     if (sameWord(gh->dataType,"bed 15"))
 	drawFeatures(vg->vg, tableName, fs, 0, FALSE);
 
 
     /* GenoLay area for track control */
     if (sameWord(gh->dataType,"bed 15"))
 	{
 	struct genoLay *pad = defaultLayoutH (fs, hghBetweenVPad,heatmapHeight(gh));
 	struct genoLay *tc = defaultLayoutH (pad, hghTrackContrlBar,heatmapHeight(gh));
 	
 	/* draw track control bar */
 	if (tc && tc->chromList)
 	    {
 	    int x = tc->chromList->x;
 	    int y = tc->chromList->y;
 	    vgBox(vg->vg,x,y,tc->picWidth, tc->picHeight,MG_GRAY);
 	    }
 	}
 
     /* Draw Feature label */
     if (ifDrawFeatureLabel(ref,ref->next))
 	{
 	struct genoLay *fsL = defaultLayoutV(fs, fs->picWidth, hghFeatureLabel);
         drawFeatureLabel(tableName, fsL ,vg->vg, MG_BLACK); 
 	}
 
     /* Set totalYOff */
     if (ifDrawFeatureLabel(ref,ref->next))
 	totalYOff += heatmapFullHeightWithLabels(gh);
     else
 	totalYOff += heatmapFullHeight(gh);
     }
 
 /* Draw meta analysis result */
 if (drawChroms)
     {
     if (ghMetaResult)
 	{
 	totalYOff += hghBetweenRowPad; 
 	offset = totalYOff; 
 	drawHgStats (vg->vg, ghMetaResult->stats, gl, offset,
 		     0,  ghMetaResult->max, colorCutoff);
 	totalYOff +=  hghBed5Height;
 	}
     }
 else
     {
     if (ghMetaResultHash)
 	{
 	totalYOff += hghBetweenRowPad; 
 	offset = totalYOff;
 	int isBlockStat = cartUsualBoolean(cart, hghPerformBlockStats, 0);
 	drawGeneSetHgStats(vg->vg, ghMetaResultHash->hash, gl, offset,  
 			   allGeneSets, 0,  3, colorCutoff, isBlockStat, 
 			   NULL, NULL);
 
 	
 	/* gene lables for meta analysis */
 	offset += hghBed5Height;
 	if (ifDrawGeneLabels())
 	    drawGeneLabels(vg->vg, gl, tableName, allGeneSets, ghMetaResultHash->hash, offset);
 	totalYOff += hghBed5Height;	
 	}
     }
 
 /* Finally, draw the labels and then the chromosomes below gl */
 if (drawChroms)
     { 
     /* Get our grayscale. */
     hMakeGrayShades(vg, shadesOfGray, maxShade);
     genoLayDrawChromLabels(gl, vg, MG_BLACK);
     genoLayDrawBandedChroms(gl, vg, database, conn, 
 			    shadesOfGray, maxShade, MG_BLACK);
     }
 else
     {
     drawGeneSetBands(gl, allGeneSets, vg, MG_BLACK);
     drawGeneSetLabels(gl, allGeneSets, vg, MG_BLACK);
     }
 
 hvGfxClose(&vg);
 }
 
 
 
 void geneSetDetailGif(struct sqlConnection *conn, struct genoLay *gl,
 		      char *psOutput)
 /* Create geneset heatmap, PCA, and feature display GIF file and HT that includes it. */
 {
 struct hvGfx *vg;
 struct tempName gifTn;
 Color shadesOfGray[10];
 int maxShade = ArraySize(shadesOfGray)-1;
 int yOffset = 2*SMALL_SPACING;
 int totalYOff = 0;
 
 struct genoHeatmap *gh= NULL;
 struct slRef *ref= NULL;
 char *db, *tableName;
 
 ref = ghList;
 if (ref == NULL)
     return;
 gh = ref->val;
 
 /* Get geneSets info */
 struct hashEl *el = hashLookup(gsHash, geneSetGroup());
 if (!el)
     return;
 
 struct genoLay *gsl = gsDetailLayout(conn, gl);
 struct sqlConnection *pathwayDbConn = getPathwayDbConn();
 struct geneSet *gs;
 
 /* Draw geneset heatmaps. */
 for (gs = allGeneSets; gs; gs = gs->next)
     {	
     trashDirFile(&gifTn, "hgh", "ideo", ".gif");
 
     int totalH=gsl->picHeight;
     int totalW=gsl->picWidth;
     totalW = totalW + cartUsualInt(cart, hghFeatureWidth, hgFeatureDefaultPixWidth); 
     totalW = totalW + hghBetweenVPad +  hghSubgroupDefaultPixWidth;
     totalW = totalW + hghBetweenVPad + hghTrackContrlBar + hghBetweenVPad;
  
-    vg = hvGfxOpenGif(totalW, totalH, gifTn.forCgi);
+    vg = hvGfxOpenGif(totalW, totalH, gifTn.forCgi, FALSE);
     
     /* Get our grayscale. */ 
     hMakeGrayShades(vg, shadesOfGray, maxShade);  
     hPrintf("<INPUT TYPE=IMAGE SRC=\"%s\" BORDER=1 WIDTH=%d HEIGHT=%d NAME=\"%s\">",
 	    gifTn.forHtml, totalW, totalH, hghClick); 
 
     gsl->pixelsPerBase = (double) gsl->picWidth / (double) gs->numGenes;
   
     totalYOff = 0;
     for (ref = ghList; ref != NULL; ref = ref->next)
 	{
 	gh = ref->val;
 
 	if (differentWord(gh->dataType,"bed 15"))
 	    continue;
 
 	//draw dataset label
 	totalYOff += hghBetweenRowPad ; 
 	struct trackLayout tl;  /* Dimensions of things, fonts, etc. */
 	trackLayoutInit(&tl, cart);
 	int labelPad =tl.fontHeight+10;
 	hvGfxTextCentered(vg,0,totalYOff,gl->picWidth, labelPad, MG_BLACK,gl->font,gh->shortLabel);
 	totalYOff += labelPad; 
 
 	db = gh->database;
 	tableName = gh->name;
 	char *probeAliases = gh->probeTable;
 	struct hash *geneHash = NULL;
 	getChromHeatmapHash(&geneHash, db, probeAliases,tableName, NULL, gs);
 	
 	geneSetOneRowLayout(gs, geneHash, 2);
 
 	if (sameWord(gh->platform, "SNP"))
 	    drawGeneSetHeatmapByPixel(vg, db, gsl, gs, geneHash, tableName,
 				      totalYOff + yOffset, TRUE, TRUE, TRUE);	
 	else
 	    drawGeneSetHeatmapByPixel(vg, db, gsl, gs, geneHash, tableName,
 				      totalYOff + yOffset, TRUE, TRUE, TRUE);
 	
 	drawPCAPlot(vg->vg, db, gs, geneHash, tableName, totalYOff + yOffset);
 
 
 	/* generate a new gl that is only for the specific panel of the heatmap gh */
 	/* TODO */
 	struct genoLay *newGl=AllocA(struct genoLay);
 	newGl->picWidth = gsl->picWidth;
 	newGl->picHeight = heatmapHeight(gh);
 	newGl->font = gsl->font;
 	struct genoLayChrom *newChrom = AllocA(struct genoLayChrom);
 	
 	struct genoLayChrom *chrom = gsl->chromList; 
 	
 	newChrom->next = NULL;
 	newChrom->y = totalYOff;
 	newChrom->x = chrom->x;
 	newChrom->width = gsl->picWidth;
 	newChrom->height = heatmapHeight(gh);
 	newGl->chromList = newChrom;
 	
 	/* GenoLay area for subgroup labeling */
 	struct genoLay *subGl = subgroupLayout (gh,newGl);
 	if (!subGl)
 	    subGl = defaultLayoutH (newGl, 0, 0);
 	
 	/* draw subgroup color lable */
 //	if (gotAdvFilter(theDataset,gh->patDb))
 //	    drawSubgroups(vg->vg, tableName, subGl, 0);
 	
 	
 	/* GenoLay area for feature sorter */
 	struct genoLay *fs = featureLayout(gh, subGl);
 	if (!fs)
 	    fs = defaultLayoutH (subGl, 0, 0);
 	
 	/* draw feature sorter */
 	if (sameWord(gh->dataType,"bed 15"))
 	    drawFeatures(vg->vg, tableName, fs, 0, FALSE);
 	
 	/* GenoLay area for track control */
 	struct genoLay *pad = defaultLayoutH (fs, hghBetweenVPad,heatmapHeight(gh));
 	struct genoLay *tc = defaultLayoutH (pad, hghTrackContrlBar,heatmapHeight(gh));
 
 	/* draw track control bar */
 	if (tc && tc->chromList)
 	    {
 	    int x = tc->chromList->x;
 	    int y = tc->chromList->y;
 	    vgBox(vg->vg,x,y,tc->picWidth, tc->picHeight,MG_GRAY);
 	    }
 	
 	/*draw Feature label */
 	if (ifDrawFeatureLabel(ref,ref->next))
 	    totalYOff +=heatmapFullHeightWithLabels(gh);
 	else
 	    totalYOff += heatmapFullHeight(gh);	
 	}
     
     hvGfxClose(&vg);
     hPrintf("<BR>");
     }
 
 hFreeConn(&pathwayDbConn);
 }
 
 void setupDataAfterMainInterface()
 /* set up gene sets, only apply to gene set display mode */
 {
 if (sameWord(displayType(),"gene set"))
     {
     if (cartVarExists(cart,hghGeneSetZoomOut))
 	cartRemove(cart, hghSelectedPathway);
     
     char *pathwayNames = getGeneSetMembers();
     char *previousPathways = cartUsualString(cart, "previous pathways", "");
     if (pathwayNames && differentWord(pathwayNames,previousPathways))
 	cartRemove(cart, hghSelectedPathway);
     cartSetString(cart, "previous pathways", pathwayNames);
 
     allGeneSets = getAllGeneSets();
     }
 }
 
 void graphDropdown(char *varName, char *curVal, char *js)
 //void graphDropdown(struct sqlConnection *conn, char *varName, char *curVal, char *js)
 /* Make a drop-down with available chrom graphs */
 {
 char **menu, **values;
 int totalCount;
 
 if ( sameWord(varName,hghDataSet))
     {
     /* build set hash */
     struct sqlConnection *conn = hAllocConn(database);
     struct hash *hash = newHash(0);
     char *datasetRaName = dataSetRaName();
     struct hash *raList = readRa(datasetRaName), *raHash = NULL;
     struct hashEl *el = NULL;
     for (raHash = raList; raHash != NULL; raHash = raHash->next)
 	{
 	el = hashLookup(raHash,"group");
 	if (el)
 	    {
 	    struct slName *groups = slNameListFromComma(el->val);
 	    struct slName *group;
 	    for (group = groups; group; group= group->next)
 		{
 		if (hashLookup(hash, group->name))
 		    continue;
 		if (hashLookup(raHash,"hide"))
 		    continue;
 		el = hashLookup(raHash,"name");
 		if (sqlTableExists(conn, (char *) el->val))
 		    hashAdd(hash, group->name, NULL);
 		}
 	    }
 	}
 
     /* use group hash to build menu */
     totalCount = hash->elCount+1;
     AllocArray(menu, totalCount);
     AllocArray(values, totalCount);
     menu[0]=values[0]="select from the drop down list";
 
     struct hashEl *elList = hashElListHash(hash);
     int i =1;
     for (el= elList; el; el= el->next)
 	{
 	menu[i]=values[i] = el->name;
 	i++;
 	}
 
     hFreeConn(&conn);
     /* free memory */
     hashElFreeList(&elList);
     freeHash(&hash);
     }
 else if ( sameWord(varName, hghDisplayType))
     {
     totalCount = 2;
     AllocArray(menu, totalCount);
     AllocArray(values, totalCount);
     menu[0]=values[0] = "chromosome";
     menu[1]=values[1] = "gene set";
     }
 else if ( sameWord(varName, hghGeneSetGroup))
     {
     int realCount =0;
 
     if (sameString(displayType(),"gene set"))
 	realCount = slCount(gsList);
 
     if (realCount==0)
 	totalCount =1;
     else
 	totalCount = realCount +1;
 
     AllocArray(menu, totalCount);
     AllocArray(values, totalCount);
 	
     if (realCount ==0)
 	{
 	menu[0]="no pathways in chromosome mode";
 	values[0]="";
 	}
     else
 	{
 	struct geneSetGroup *gs;
 	int i = 0;
 	for (gs = gsList; gs != NULL; gs = gs->next)
 	    {
 	    menu[i] = gs->shortLabel;
 	    values[i] = gs->name;
 	    ++i;
 	    }            
 	menu[i]=values[i]="User Defined";
 
 	if (sameString(curVal, ""))
 	    {  /* Hack to set a default gene set when userswitches from 
 		* 'chromosome' to 'gene set' -- Without this hack, switching leaves
 		* hghGeneSetGroup set to "" and a blank heatmap drawn */
 
 	    curVal = cloneString(values[0]);
 	    cartSetString(cart, hghGeneSetGroup, curVal);
 	    }
 	}
     }
 else
     return;
 
 cgiMakeDropListFull(varName, menu, values, totalCount, curVal, js);
 freez(&menu);
 freez(&values);
 }
 
 static void addThresholdHeatmapCarries(struct dyString *dy)
 /* Add javascript that carries over threshold and graph vars
  * to new form. */
 {
 jsDropDownCarryOver(dy, hghDataSet);
 }
 
 static void addDisplayTypeCarry(struct dyString *dy)
 /* Add javascript that carriers over display type to new form */
 {
 jsDropDownCarryOver(dy, hghDisplayType);
 }
 
 static void addGeneSetGroupCarry(struct dyString *dy)
 /* Add javascript that carriers over display type to new form */
 {
 jsDropDownCarryOver(dy, hghGeneSetGroup);
 }
  
 static struct dyString *onChangeStart()
 /* Return common prefix to onChange javascript string */
 {
 struct dyString *dy = jsOnChangeStart();
 addThresholdHeatmapCarries(dy);
 addDisplayTypeCarry(dy);
 addGeneSetGroupCarry(dy);
 return dy;
 }
 
 /* static char *onChangeClade() */
   /* Return javascript executed when they change clade. */
 /*{
 struct dyString *dy = onChangeStart();
 jsDropDownCarryOver(dy, "clade");
 dyStringAppend(dy, " document.hiddenForm.org.value=0;");
 dyStringAppend(dy, " document.hiddenForm.db.value=0;");
 return jsOnChangeEnd(&dy);
 }
 */
 
 /* Return javascript executed when they change organism. */
 /*
 static char *onChangeOrg()
 {
 struct dyString *dy = onChangeStart();
 jsDropDownCarryOver(dy, "clade");
 jsDropDownCarryOver(dy, "org");
 dyStringAppend(dy, " document.hiddenForm.db.value=0;");
 return jsOnChangeEnd(&dy);
 }
 */
 
 static char *onChangeSelection()
 {
 struct dyString *dy = onChangeStart();
 return jsOnChangeEnd(&dy);
 }
 
 static void saveOnChangeOtherFunction()
 
 /* Write out Javascript function to save vars in hidden
  * form and submit. */
 {
 struct dyString *dy = dyStringNew(0);
 addThresholdHeatmapCarries(dy);
 addDisplayTypeCarry(dy);
 addGeneSetGroupCarry(dy);
 jsDropDownCarryOver(dy, "clade");
 jsDropDownCarryOver(dy, "org");
 jsDropDownCarryOver(dy, "db");
 char *js = jsOnChangeEnd(&dy);
 chopSuffixAt(js, '"');
 hPrintf("<SCRIPT>\n");
 hPrintf("function changeOther()\n");
 hPrintf("{\n");
 hPrintf("if (!submitted)\n");
 hPrintf("{\n");
 hPrintf("submitted=true;\n");
 hPrintf("%s\n", js);
 hPrintf("}\n");
 hPrintf("}\n");
 hPrintf("</SCRIPT>\n");
 }
 
 // static char *onChangeOther() 
 /* Return javascript executed when they change database. */
 /* {
 return "onChange=\"changeOther();\"";
 }
 */
 
 boolean renderGraphic(struct sqlConnection *conn, char *psOutput)
 /* draw just the graphic */
 {
 struct genoLay *gl;
 boolean result = FALSE;
 if (ghList != NULL)
     {
     /* Get genome layout.  This can fail so it is wrapped in an error
      * catcher. */
     struct errCatch *errCatch = errCatchNew();
 
     if (errCatchStart(errCatch))
 	{
 	gl = ggLayout(conn);
 	/* Draw picture. Enclose in table to add a couple of pixels between
 	 * it and controls on IE. */
 
         // TODO: come up with details page and perform, uncomment below line to draw PCA plots  
 //	geneSetDetailGif(conn, gl, psOutput); 
 
 	genomeGif(conn, gl, psOutput);
 
 	result = TRUE;
 	}
     errCatchEnd(errCatch);
     if (errCatch->gotError)
 	 warn(errCatch->message->string);
     errCatchFree(&errCatch); 
     }
 else
     {
     hPrintf("<BR>No graph data is available. Use the drop down list or the configuration buttom to select a data set.");
     }
 return result;
 }
 
 void handlePostscript(struct sqlConnection *conn)
 /* Deal with Postscript output. */
 {
 struct tempName psTn;
 char *pdfFile = NULL;
 trashDirFile(&psTn, "hgh", "hgh", ".eps");
 cartWebStart(cart, database, "%s Genome Heatmaps", genome);
 printf("<H1>PostScript/PDF Output</H1>\n");
 printf("PostScript images can be printed at high resolution "
        "and edited by many drawing programs such as Adobe "
        "Illustrator.<BR>");
 
 boolean result = renderGraphic(conn, psTn.forCgi);
 if (result)
     {
     printf("<A HREF=\"%s\">Click here</A> "
 	   "to download the current browser graphic in PostScript.  ", psTn.forCgi);
     pdfFile = convertEpsToPdf(psTn.forCgi);
     if(pdfFile != NULL)
 	{
 	printf("<BR><BR>PDF can be viewed with Adobe Acrobat Reader.<BR>\n");
 	printf("<A TARGET=_blank HREF=\"%s\">Click here</A> "
 	       "to download the current browser graphic in PDF.", pdfFile);
 	}
     else
 	printf("<BR><BR>PDF format not available");
     freez(&pdfFile);
     }
 cartWebEnd();
 }
 
 
 void mainPage(struct sqlConnection *conn)
 /* Do main page of application:  hotlinks bar, controls, graphic. */
 {
 char *scriptName = "/cgi-bin/hgHeatmap";
 
 cartWebStart(cart, database, "UCSC Cancer Genome Heatmaps");
 
 /* Start form and save session var. */
 hPrintf("<FORM ACTION=\"..%s\" NAME=\"mainForm\" METHOD=POST>\n", scriptName);
 cartSaveSession(cart);
 
 /* Write some javascript functions */
 jsWriteFunctions();
 saveOnChangeOtherFunction();
 
 /* Print clade, genome and assembly line. */
 //boolean gotClade = hGotClade();
 //char *jsOther = onChangeOther();
 {
 hPrintf("<TABLE>");
 /*
 if (gotClade)
     {
     printCladeListHtml(hGenome(database), onChangeClade());
     printGenomeListForCladeHtml(database, onChangeOrg());
     }
 else
     {
     printGenomeListHtml(database, onChangeOrg());
     }
 htmlNbSpaces(3);
 */
 
 database ="hg18";
 //printAssemblyListHtml(database, onChangeSelection()); 
 hPrintf("<B>Genome:</B> Hg18");
 
 /* Show data set selector. */
 htmlNbSpaces(3);
 hPrintf("<B>select:</B>\n");
 char *curVal = dataSetName();
 graphDropdown (hghDataSet, curVal, onChangeSelection());  //jsOnChangeEnd(&dy)); //jsOther); 
 
 /* Display mode. */
 htmlNbSpaces(3);
 hPrintf("<B>display by:</B>\n");
 curVal = displayType();
 graphDropdown(hghDisplayType, curVal, onChangeSelection()) ;//jsOther);
 
 /* Show display mode specific data */
 curVal = geneSetGroup();
 hPrintf("<B>Pathways:</B>\n");
 graphDropdown(hghGeneSetGroup, curVal, onChangeSelection());//jsOther);
 
 hPrintf("</TD></TR>\n");
 hPrintf("</TABLE>\n");
 }
 
 cgiMakeButton(hghConfigure, "configure");
 //hPrintf("<BR>");
 
 if (sameWord(displayType(),"gene set") && cartUsualString(cart, hghSelectedPathway, NULL)) 
     cgiMakeButton(hghGeneSetZoomOut, "zoom out");
 hPrintf("<BR>");
 
 if (DEBUG)
 {
 //draw check box
 char varName[128];
 safef(varName, sizeof(varName), "%s.vis", hghScoreOutput);
 boolean isOutput = cartUsualBoolean(cart, varName, FALSE);
 hPrintf("Score all, Output");
 cgiMakeCheckBox(varName, isOutput);
 
 //gene or pathway
 safef(varName, sizeof(varName), "%s", hghScoreTypeOutput);
 char *menu[3];
 menu[0]="gene";
 menu[1]="pathway";
 menu[2]="metapathway";
 char *type= cartUsualString(cart, varName, "");
 cgiMakeDropList(varName, menu, 3, type);
 cgiMakeSubmitButton();
 }
 
 hPrintf("<TABLE CELLPADDING=2><TR><TD>\n");
 
 setupDataAfterMainInterface();
 
 runStatTests();
 
 boolean result = renderGraphic(conn, NULL);
 
 hPrintf("</TD></TR></TABLE>\n");
 if (result)
     /* Write a little click-on-help */
     if (sameWord(displayType(), "chromosome"))
 	hPrintf("<i>Click on a chromosome to open Genome Browser at that position.</i><BR>");
 
 cgiMakeSubmitButton();
 hPrintf("<Br>");
 
 if (sameWord(displayType(), "gene set"))
 {
 hPrintf("<B>A user defined gene set / pathway.</B> \
 Enter comma separated gene identifiers. Example: ERBB2,ESR1,AKT1");
 hPrintf("<Br>");
 char *varText = cartUsualString(cart, hghUserGeneList, "");
 cgiMakeTextArea(hghUserGeneList, varText, 1, 80);
 hPrintf("<Br>");
 }
 
 if (sameWord(displayType(), "gene set"))
 {
 hPrintf("<B>Enter specific pathway names.</B> Example: BRCA_ER_POS,h_her2Pathway");
 hPrintf("<Br>");
 char *varText = cartUsualString(cart, hghUserGeneSetList, "");
 cgiMakeTextArea(hghUserGeneSetList, varText, 1, 80);
 hPrintf("<Br>");
 }
 
 
 if (DEBUG)
 {
 hPrintf("<B>only be used for DEBUGGING purpose</B> Display only these patients in the following order, format is comma-seperated patient list.\
  Example: 1001,1002");
 hPrintf("<Br>");
 char *varText = cartUsualString(cart, hghDebugUserPatList , "");
 cgiMakeTextArea(hghDebugUserPatList, varText, 1, 80);
 hPrintf("<Br>");
 }
 
 
 if (DEBUG)
 {
 hPrintf("<B>only be used for DBUGGING purpose</B> Display only these samples in the following order</B>, format is comma-seperated sample list.\
  Example:  209389,209515");
 hPrintf("<Br>");
 char *varText = cartUsualString(cart, hghDebugUserSpList , "");
 cgiMakeTextArea(hghDebugUserSpList, varText, 2, 80);
 hPrintf("<Br>");
 }
 
 
 hPrintf("</FORM>\n");
 
 /* Hidden form - fo the benefit of javascript. */
 {
 /* Copy over both the regular, non-changing variables, and
  * also all the source/color pairs that depend on the
  * configuration. */
 static char *regularVars[] = {
     "clade", "org", "db", hghHeatmap, hghDataSet, hghDisplayType, hghGeneSetGroup
 };
 int regularCount = ArraySize(regularVars);
 jsCreateHiddenForm(cart, scriptName, regularVars, regularCount);
 }
 
 cartWebEnd();
 
 }