Index: src/hg/hgTracks/bedGraph.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/hg/hgTracks/bedGraph.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -b -B -U 1000000 -r1.21 -r1.22
--- src/hg/hgTracks/bedGraph.c	25 Mar 2010 17:46:01 -0000	1.21
+++ src/hg/hgTracks/bedGraph.c	27 Apr 2010 23:31:41 -0000	1.22
@@ -1,271 +1,275 @@
 /* bedGraph - stuff to handle loading and display of
  * bedGraph type tracks in browser.   Will be graphing a specified
  *	column of a bed file.
  */
 
 #include "common.h"
 #include "hash.h"
 #include "linefile.h"
 #include "jksql.h"
 #include "hdb.h"
 #include "hgTracks.h"
 #include "wiggle.h"
 #include "scoredRef.h"
 #include "customTrack.h"
 #include "wigCommon.h"
 
 static char const rcsid[] = "$Id$";
 
 /*	The item names have been massaged during the Load.  An
  *	individual item may have been read in on multiple table rows and
  *	had an extension on it to make it unique from the others.  Also,
  *	each different zoom level had a different extension name.
  *	All these names were condensed into the root of the name with
  *	the extensions removed.
  */
 static char *bedGraphName(struct track *tg, void *item)
 /* Return name of bedGraph level track. */
 {
 struct bedGraphItem *bg = item;
 return bg->name;
 }
 
 void ctBedGraphLoadItems(struct track *tg)
 {
 /*	load custom bedGraph track data	*/
 
 /*	Verify this is a custom track	*/
 if (tg->customPt == (void *)NULL)
     errAbort("ctBedGraphLoadItems: did not find a custom wiggle track: %s", tg->mapName);
 
 errAbort("custom track bedGraph load items not yet implemented");
 }
 
 /*	bedGraphLoadItems - an ordinary bed load, but we are interested
  *		in only the chrom, start, end, and the graphColumn
  */
 static void bedGraphLoadItems(struct track *tg)
 {
 struct sqlConnection *conn;
 struct sqlResult *sr = (struct sqlResult *) NULL;
 char **row = (char **)NULL;
 int rowOffset = 0;
 struct bedGraphItem *bgList = NULL;
 int itemsLoaded = 0;
 int colCount = 0;
 struct wigCartOptions *wigCart = (struct wigCartOptions *) tg->extraUiData;
 int graphColumn = 5;
 char *tableName;
 
 if(sameString(tg->mapName, "affyTranscription"))
     wigCart->colorTrack = "affyTransfrags";
 graphColumn = wigCart->graphColumn;
 
 
 #ifndef GBROWSE
 if (tg->customPt)
     {
     struct customTrack *ct = (struct customTrack *) tg->customPt;
     tableName = ct->dbTableName;
     conn = hAllocConn(CUSTOM_TRASH);
     }
 else 
 #endif /* GBROWSE */
     {
     tableName = tg->mapName;
     conn = hAllocConnTrack(database, tg->tdb);
     }
 
 sr = hRangeQuery(conn, tableName, chromName, winStart, winEnd, NULL,
 	&rowOffset);
 
 colCount = sqlCountColumns(sr) - rowOffset;
 /*	Must have at least four good columns	*/
 if (colCount < 4)
     errAbort("bedGraphLoadItems: table %s only has %d data columns, must be at least 4", tableName, colCount);
 
 if (colCount < graphColumn)
     errAbort("bedGraphLoadItems: table %s only has %d data columns, specified graph column %d does not exist",
 	tableName, colCount, graphColumn);
 
 /*	before loop, determine actual row[graphColumn] index */
 graphColumn += (rowOffset - 1);
 
 while ((row = sqlNextRow(sr)) != NULL)
     {
     struct bedGraphItem *bg;
     struct bed *bed;
 
     ++itemsLoaded;
 
     /*	load chrom, start, end	*/
     bed = bedLoadN(row+rowOffset, 3);
 
     AllocVar(bg);
     bg->start = bed->chromStart;
     bg->end = bed->chromEnd;
     if ((colCount > 4) && ((graphColumn + rowOffset) != 4))
 	bg->name = cloneString(row[3+rowOffset]);
     else
 	{
 	char name[128];
 	safef(name,ArraySize(name),"%s.%d", bed->chrom, itemsLoaded);
 	bg->name = cloneString(name);
 	}
     bg->dataValue = sqlFloat(row[graphColumn]);
     /* filled in by DrawItems	*/
     bg->graphUpperLimit = wigEncodeStartingUpperLimit;
     bg->graphLowerLimit = wigEncodeStartingLowerLimit;
     slAddHead(&bgList, bg);
     bedFree(&bed);
     }
 
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 
 slReverse(&bgList);
 tg->items = bgList;
 }	/*	bedGraphLoadItems()	*/
 
 static void bedGraphFreeItems(struct track *tg) {
 #if defined(DEBUG)
 snprintf(dbgMsg, DBGMSGSZ, "I haven't seen bedGraphFreeItems ever called ?");
 wigDebugPrint("bedGraphFreeItems");
 #endif
 }
 
 static void bedGraphDrawItems(struct track *tg, int seqStart, int seqEnd,
 	struct hvGfx *hvg, int xOff, int yOff, int width,
 	MgFont *font, Color color, enum trackVisibility vis)
 {
 struct bedGraphItem *wi;
 double pixelsPerBase = scaleForPixels(width);
 double basesPerPixel = 1.0;
 int i;				/* an integer loop counter	*/
 if (pixelsPerBase > 0.0)
     basesPerPixel = 1.0 / pixelsPerBase;
 
 /*	walk through all the data and prepare the preDraw array	*/
 int preDrawZero, preDrawSize;
 struct preDrawElement *preDraw = initPreDraw(width, &preDrawSize, &preDrawZero);
 for (wi = tg->items; wi != NULL; wi = wi->next)
     {
     double dataValue = wi->dataValue;	/* the data value to graph */
 
     /*	Ready to draw, what do we know:
     *	the feature being processed:
     *	chrom coords:  [wi->start : wi->end)
     *	its data value: dataValue = wi->dataValue
     *
     *	The drawing window, in pixels:
     *	xOff = left margin, yOff = top margin, h = height of drawing window
     *	drawing window in chrom coords: seqStart, seqEnd
     *	'basesPerPixel' is known, 'pixelsPerBase' is known
     */
     /*	let's check end point screen coordinates.  If they are
      *	the same, then this entire data block lands on one pixel,
      *	It is OK if these end up + or -, we do want to
      *	keep track of pixels before and after the screen for
      *	later smoothing operations
      */
     int x1 = (wi->start - seqStart) * pixelsPerBase;
     int x2 = (wi->end - seqStart) * pixelsPerBase;
 
     if (x2 > x1)
 	{
 	for (i = x1; i <= x2; ++i)
 	    {
 	    int xCoord = preDrawZero + i;
 	    if ((xCoord >= 0) && (xCoord < preDrawSize))
 		{
 		++preDraw[xCoord].count;
 		if (dataValue > preDraw[xCoord].max)
 		    preDraw[xCoord].max = dataValue;
 		if (dataValue < preDraw[xCoord].min)
 		    preDraw[xCoord].min = dataValue;
 		preDraw[xCoord].sumData += dataValue;
 		preDraw[xCoord].sumSquares += dataValue * dataValue;
 		}
 	    }
 	}
 	else
 	{	/*	only one pixel for this block of data */
 	int xCoord = preDrawZero + x1;
 	/*	if the point falls within our array, record it.
 	 *	the (wi->validCount > 0) is a safety check.  It
 	 *	should always be true unless the data was
 	 *	prepared incorrectly.
 	 */
 	if ((xCoord >= 0) && (xCoord < preDrawSize))
 	    {
 	    ++preDraw[xCoord].count;
 	    if (dataValue > preDraw[xCoord].max)
 		preDraw[xCoord].max = dataValue;
 	    if (dataValue < preDraw[xCoord].min)
 		preDraw[xCoord].min = dataValue;
 	    preDraw[xCoord].sumData += dataValue;
 	    preDraw[xCoord].sumSquares += dataValue * dataValue;
 	    }
 	}
     }	/*	for (wi = tg->items; wi != NULL; wi = wi->next)	*/
 
 /*	now we are ready to draw.  Each element in the preDraw[] array
  *	cooresponds to a single pixel on the screen
  */
 
+struct preDrawContainer *preDrawContainer;
+AllocVar(preDrawContainer);
+preDrawContainer->preDraw = preDraw;
 wigDrawPredraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis,
-	       preDraw, preDrawZero, preDrawSize, &tg->graphUpperLimit, &tg->graphLowerLimit);
+	       preDrawContainer, preDrawZero, preDrawSize, &tg->graphUpperLimit, &tg->graphLowerLimit);
 
+freeMem(preDrawContainer);
 freeMem(preDraw);
 }	/*	bedGraphDrawItems()	*/
 
 
 /*
  *	WARNING ! - track->visibility is merely the default value
  *	from the trackDb entry at this time.  It will be set after this
  *	 by hgTracks from its cart UI setting.  When called in
  *	 TotalHeight it will then be the requested visibility.
  */
 void bedGraphMethods(struct track *track, struct trackDb *tdb, 
 	int wordCount, char *words[])
 {
 struct wigCartOptions *wigCart = wigCartOptionsNew(cart, tdb, wordCount, words);
 wigCart->bedGraph = TRUE;	/*	signal to left labels	*/
 switch (wordCount)
     {
 	case 2:
 	    wigCart->graphColumn = atoi(words[1]);
 	    /*	protect against nonsense values	*/
 	    if ( (wigCart->graphColumn < 2) ||
 		(wigCart->graphColumn > 100) )
 		wigCart->graphColumn = 5; /* default score column */
 
 	    break;
 	default:
 	    wigCart->graphColumn = 5; /* default score column */
 	    break;
     } 
 
 track->minRange = wigCart->minY;
 track->maxRange = wigCart->maxY;
 track->graphUpperLimit = wigEncodeStartingUpperLimit;
 track->graphLowerLimit = wigEncodeStartingLowerLimit;
 
 track->loadItems = bedGraphLoadItems;
 track->freeItems = bedGraphFreeItems;
 track->drawItems = bedGraphDrawItems;
 track->itemName = bedGraphName;
 track->mapItemName = bedGraphName;
 track->totalHeight = wigTotalHeight;
 track->itemHeight = tgFixedItemHeight;
 
 track->itemStart = tgItemNoStart;
 track->itemEnd = tgItemNoEnd;
 track->mapsSelf = TRUE;
 track->extraUiData = (void *) wigCart;
 track->colorShades = shadesOfGray;
 track->drawLeftLabels = wigLeftLabels;
 /*	the lfSubSample type makes the image map function correctly */
 track->subType = lfSubSample;     /*make subType be "sample" (=2)*/
 
 }	/*	bedGraphMethods()	*/

