Example #1
0
void drawUseBamWarning(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg,
                 int xOff, int yOff, int width, MgFont *font, Color color,
                 enum trackVisibility vis)
/* Draw a message saying that the code needs to be built with USE_BAM=1. */
{
char message[512];
safef(message, sizeof(message),
      "Get samtools(.sourceforge.net) and recompile kent/src with USE_BAM=1");
Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
hvGfxBox(hvg, xOff, yOff, width, tg->heightPer, yellow);
hvGfxTextCentered(hvg, xOff, yOff, width, tg->heightPer, MG_BLACK, font, message);
}
Example #2
0
void bigDrawWarning(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg,
                 int xOff, int yOff, int width, MgFont *font, Color color,
                 enum trackVisibility vis)
/* Draw the network error message */
{
char message[1024];
Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
char *errMsg = bigWarnReformat(tg->networkErrMsg);
char *nl = errMsg;
int sl = strlen(errMsg);
// in some cases, cannot use tg-> values, so recalc local equivalents. 
int heightPer = tl.fontHeight;        /* Height per item line minus border. */
int lineHeight = heightPer+4;         /* Height per item line including border. */ 
if (lineHeight > tg->height)
    lineHeight = tg->height;
int n = bigWarnNumLines(errMsg);      /* Lines of warning text */
int m = tg->height / lineHeight;      /* Lines of text space available */
if (m < 1) 
    m = 1;
// make yellow background to draw user's attention to the err msg
if (!sameOk(parentContainerType(tg), "multiWig")) // unless multiwig has already done it.
    hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow);
// leading blank lines if any
int bl = (m-n)/2;   
int i;
for(i=0;i<bl;++i)
    yOff += lineHeight;
int l = 0;
while (TRUE)
    {
    char *msg = nl;
    nl = strchr(nl,'\n');
    if (nl)
	nl[0] = 0;
    if (nl || ((sl > 0) && (errMsg[sl-1]!='\n')))
	{  
	safef(message, sizeof(message), "%s", msg);
	hvGfxTextCentered(hvg, xOff, yOff, width, lineHeight, MG_BLACK, font, message);
	yOff += lineHeight;
        ++l;
        if (l > n)
	    break;
        if (l > m)
	    break;
	}
    if (!nl)
	break;
    ++nl;
    }
freeMem(errMsg);
}
Example #3
0
Color pubsItemColor(struct track *tg, void *item, struct hvGfx *hvg)
/* get color from extra field */
{
//pubsParseClassColors();
struct linkedFeatures *lf = item;
pubsAddExtra(tg, lf);

struct pubsExtra* extra = lf->extra;
if (extra==NULL || (extra->color==NULL && extra->shade==-1))
    return MG_BLACK;

if (extra->shade != -1)
    return shadesOfBlue[extra->shade];
else
    {
    //printf("got item color %d", extra->color->r);
    return hvGfxFindRgb(hvg, extra->color);
    }
}
struct hvGfx *oneTrackMakeTrackHvg(char *trackName, char *gifName)
/* Set up a single track, load it, draw it and return the graphics object: */
{
char *visStr = cloneString(
	cartUsualString(cart, trackName, hTrackOpenVis(trackName)) );
cartSetString(cart, trackName, visStr);
struct trackDb *tdb = hTrackDbForTrack(trackName);
tdbSortPrioritiesFromCart(cart, &tdb);
if(tdb->subtracks)
    tdbSortPrioritiesFromCart(cart, &(tdb->subtracks));
struct track *tg = trackFromTrackDb(tdb);
tg->visibility = hTvFromString(visStr);
trackList = tg;

tg->loadItems(tg);
limitVisibility(tg);
int height = tg->totalHeight(tg, tg->limitedVis);

struct hvGfx *hvg = hvGfxOpenGif(insideWidth, height, gifName, TRUE);
initColors(hvg);
findTrackColors(hvg, tg);

/* This is the only image we'll draw, so offset=(0,0). */
int xOff = 0, yOff = 0;
MgFont *font = tl.font;
hvGfxSetClip(hvg, xOff, yOff, insideWidth, tg->height);
tg->drawItems(tg, winStart, winEnd, hvg, xOff, yOff, insideWidth, font,
	      hvGfxFindRgb(hvg, &tg->color), tg->limitedVis);

/* MEMORY LEAK -- Freeing items slows hgTracks down unacceptably so we
 * don't do it, and it has become vestigial.  For example, wigFreeItems 
 * is a no-op because the author noted that it is never invoked. */
#ifdef SLOW
tg->freeItems(tg);
#endif /* SLOW */

return hvg;
}
Example #5
0
static void cgDrawEither(struct track *tg, int seqStart, int seqEnd,
        struct hvGfx *hvg, int xOff, int yOff, int width,
        MgFont *font, Color color, enum trackVisibility vis,
        char *binFileName)
/* Draw chromosome graph - either built in or not. */
{
struct chromGraphSettings *cgs = tg->customPt;
int x,y,lastX=0,lastY=0, llastX = 0, llastY = 0;
int height = tg->height;
int maxGapToFill = cgs->maxGapToFill;
int lastPos = -maxGapToFill-1;
double minVal = cgs->minVal;
double yScale = (height-1)/(cgs->maxVal - minVal);
double xScale = scaleForPixels(width);
Color myColor = cgColorLikeHgGenome(tg, hvg);

/* Draw background lines in full mode. */
if (vis == tvFull && cgs->linesAtCount != 0)
    {
    int i;
    Color lightBlue = hvGfxFindRgb(hvg, &guidelineColor);
    for (i=0; i<cgs->linesAtCount; ++i)
        {
	y = height - 1 - (cgs->linesAt[i] - minVal)*yScale + yOff;
	hvGfxBox(hvg, xOff, y, width, 1, lightBlue);
	}
    }

if (binFileName)
    {
    struct chromGraphBin *cgb = chromGraphBinOpen(binFileName);
    if (chromGraphBinSeekToChrom(cgb, chromName))
	{
	int seqStartMinus = seqStart - cgs->maxGapToFill;
	while (chromGraphBinNextVal(cgb))
	    {
	    int pos = cgb->chromStart;
	    if (pos >= seqStartMinus)
		{
		double val = cgb->val;
		x = (pos - seqStart)*xScale + xOff;
		y = height - 1 - (val - minVal)*yScale + yOff;
		if (x >= xOff)
		    {
		    if (pos - lastPos <= maxGapToFill)
			{
			if (llastX != lastX || llastY != lastY || lastX != x || lastY != y)
			    hvGfxLine(hvg, lastX, lastY, x, y, myColor);
			}
		    else
			hvGfxDot(hvg, x, y, myColor);
		    }
		llastX = lastX;
		llastY = lastY;
		lastX = x;
		lastY = y;
		lastPos = pos;
		if (pos >= seqEnd)
		    break;
		}
	    }
	}
    }
else
    {
    struct sqlConnection *conn = hAllocConn(database);
    char query[512];
    struct sqlResult *sr;
    char **row;
    /* Construct query.  Set up a little more than window so that
     * we can draw connecting lines. */
    sqlSafef(query, sizeof(query),
	"select chromStart,val from %s "
	"where chrom='%s' and chromStart>=%d and chromStart<%d",
	tg->table, chromName,
	seqStart - cgs->maxGapToFill, seqEnd + cgs->maxGapToFill);
    sr = sqlGetResult(conn, query);

    /* Loop through drawing lines from one point to another unless
     * the points are too far apart. */
    while ((row = sqlNextRow(sr)) != NULL)
	{
	int pos = sqlUnsigned(row[0]);
	double val = atof(row[1]);
	x = (pos - seqStart)*xScale + xOff;
	y = height - 1 - (val - minVal)*yScale + yOff;
	if (x >= xOff)
	    {
	    if (pos - lastPos <= maxGapToFill)
		{
		if (llastX != lastX || llastY != lastY || lastX != x || lastY != y)
		    hvGfxLine(hvg, lastX, lastY, x, y, myColor);
		}
	    else
		hvGfxDot(hvg, x, y, myColor);
	    }
	llastX = lastX;
	llastY = lastY;
	lastX = x;
	lastY = y;
	lastPos = pos;
	if (pos >= seqEnd)
	    break;
	}
    sqlFreeResult(&sr);
    hFreeConn(&conn);
    }

/* Do map box */
xOff = hvGfxAdjXW(hvg, xOff, width);

char *encodedTrack = cgiEncode(tg->track);
if (theImgBox && curImgTrack)
    {
    char link[512];     // FIXME: winStart/winEnd are not right when using a portal
    safef(link,sizeof(link),"%s&c=%s&o=%d&t=%d&g=%s", hgcNameAndSettings(),
        chromName, winStart, winEnd, encodedTrack);
#ifdef IMAGEv2_SHORT_MAPITEMS
    if (xOff < insideX && xOff+width > insideX)
        warn("cgDrawEither(%s) map item spanning slices. LX:%d TY:%d RX:%d BY:%d  link:[%s]",
             encodedTrack,xOff, yOff, xOff+width, yOff+height, link);
#endif//def IMAGEv2_SHORT_MAPITEMS
    imgTrackAddMapItem(curImgTrack,link,NULL,xOff,yOff,xOff+width,yOff+height,tg->track);
    }
else
    {
    hPrintf("<AREA SHAPE=RECT COORDS=\"%d,%d,%d,%d\" ", xOff, yOff, xOff+width,
            yOff+height);
    hPrintf("HREF=\"%s&o=%d&t=%d&g=%s&c=%s&l=%d&r=%d&db=%s&pix=%d\">\n",
            hgcNameAndSettings(), winStart, winEnd, encodedTrack, chromName, winStart, winEnd,
            database, tl.picWidth);
    }
}
static void wiggleLinkedFeaturesDraw(struct track *tg, 
	int seqStart, int seqEnd,
struct hvGfx *hvg, int xOff, int yOff, int width, 
	MgFont *font, Color color, enum trackVisibility vis)
	/* Currently this routine is adapted from Terry's 
	* linkedFeatureSeriesDraw() routine.
	* It is called for 'sample' tracks as specified in the trackDb.ra.
	* and it looks at the cart to decide whether to interpolate, fill blocks,
	* and use anti-aliasing.*/
{
	int i;
	struct linkedFeatures *lf;
	struct simpleFeature *sf;
	int y = yOff;
	int heightPer = tg->heightPer;
	int lineHeight = tg->lineHeight;
	int x1,x2;
	boolean isFull = (vis == tvFull);
	Color bColor = tg->ixAltColor;
	double scale = scaleForPixels(width);
	int prevX = -1;
	int gapPrevX = -1;
	double prevY = -1;
	double y1 = -1, y2;
	int ybase;
	int sampleX, sampleY; /* A sample in sample coordinates. 
						  * Sample X coordinate is chromosome coordinate.
						  * Sample Y coordinate is usually 0-1000 */
	int binCount = 1.0/tg->scaleRange;   /* Maximum sample Y coordinate. */
	int bin;	      /* Sample Y coordinates are first converted to
					  * bin coordinates, and then to pixels.  I'm not
					  * totally sure why.  */



	int currentX, currentXEnd, currentWidth;

	int leftSide, rightSide;

	int noZoom = 1;
	enum wiggleOptEnum wiggleType;
	char *interpolate = NULL;
	char *aa = NULL; 
	boolean antiAlias = FALSE;
	int fill; 
	int lineGapSize;
	double min0, max0;

	char o1[128]; /* Option 1 - linear interp */
	char o2[128]; /* Option 2 - anti alias */
	char o3[128]; /* Option 3 - fill */
	char o4[128]; /* Option 4 - minimum vertical range cutoff of plot */	
	char o5[128]; /* Option 5 - maximum vertical range cutoff of plot */
	char o6[128]; /* Option 6 - max gap where interpolation is still done */
	char cartStr[64];
	char *fillStr;

	double hFactor;
	double minRange, maxRange;
	double minRangeCutoff, maxRangeCutoff;


	Color gridColor = hvGfxFindRgb(hvg, &guidelineColor); /* for horizontal lines*/

	lf=tg->items;    
	if(lf==NULL) return;

	//take care of cart options
	safef( o1, 128,"%s.linear.interp", tg->track);
	safef( o2, 128, "%s.anti.alias", tg->track);
	safef( o3, 128,"%s.fill", tg->track);
	safef( o4, 128,"%s.min.cutoff", tg->track);
	safef( o5, 128,"%s.max.cutoff", tg->track);
	safef( o6, 128,"%s.interp.gap", tg->track);

	interpolate = cartUsualString(cart, o1, "Linear Interpolation");
	wiggleType = wiggleStringToEnum(interpolate);
	aa = cartUsualString(cart, o2, "on");
	antiAlias = sameString(aa, "on");

	//don't fill gcPercent track by default (but fill others)
	if(sameString( tg->table, "pGC") && sameString(database,"zooHuman3"))
	{
		fillStr = cartUsualString(cart, o3, "0");
	}
	else
	{
		fillStr = cartUsualString(cart, o3, "1");
	}
	fill = atoi(fillStr);
	cartSetString(cart, o3, fillStr );

	//the 0.1 is so the label doesn't get truncated with integer valued user input min
	//display range.
	minRangeCutoff = max( atof(cartUsualString(cart,o4,"0.0"))-0.1, tg->minRange );
	maxRangeCutoff = min( atof(cartUsualString(cart,o5,"1000.0"))+0.1, tg->maxRange);

	lineGapSize = atoi(cartUsualString(cart, o6, "200"));

	//update cart settings to reflect truncated range cutoff values
	cartSetString( cart, "win", "F" );
	safef( cartStr, 64, "%g", minRangeCutoff );
	cartSetString( cart, o4, cartStr );
	safef( cartStr, 64, "%g", maxRangeCutoff );
	cartSetString( cart, o5, cartStr );

	heightPer = tg->heightPer+1;
	hFactor = (double)heightPer*tg->scaleRange;

	//errAbort( "min=%g, max=%g\n", minRangeCutoff, maxRangeCutoff );


	if( sameString( tg->table, "zoo" ) || sameString( tg->table, "zooNew" ) )
		binCount = binCount - 100;    //save some space at top, between each zoo species

	minRange = whichSampleBin( minRangeCutoff, tg->minRange, tg->maxRange, binCount );
	maxRange = whichSampleBin( maxRangeCutoff, tg->minRange, tg->maxRange, binCount );

	//errAbort( "(%g,%g) cutoff=(%g,%g)\n", tg->minRange, tg->maxRange, minRangeCutoff, maxRangeCutoff );


	if( sameString( tg->table, "zoo" ) || sameString( tg->table, "zooNew" ) )
	{
		/*Always interpolate zoo track (since gaps are explicitly defined*/
		lineGapSize = -1;
	}
	else if( tg->minRange == 0 && tg->maxRange == 8 )    //range for all L-score tracks
	{
		if( isFull )
		{
			min0 = whichSampleNum( minRange, tg->minRange, tg->maxRange, binCount );
			max0 = whichSampleNum( maxRange, tg->minRange, tg->maxRange,  binCount );
			for( i=1; i<=6; i++ )
				drawWiggleHorizontalLine(hvg, (double)i, min0, max0,
				binCount, y, hFactor, heightPer, gridColor );
		}
	}

	for(lf = tg->items; lf != NULL; lf = lf->next) 
	{
		gapPrevX = -1;
		prevX = -1;
		ybase = (int)((double)y+hFactor+(double)heightPer);


		for (sf = lf->components; sf != NULL; sf = sf->next)
		{
			sampleX = sf->start;
			sampleY = sf->end - sampleX;	// Stange encoding but so it is. 
			// It is to deal with the fact that
			// for a BED: sf->end = sf->start + length
			// but in our case length = height (or y-value)
			// so to recover height we take
			// height = sf->end - sf->start.
			// Otherwise another sf variable would 
			// be needed.


			/*mapping or sequencing gap*/
			if (sampleY == 0)
			{
				bin = -whichSampleBin( (int)((maxRange - minRange)/5.0+minRange), 
					minRange, maxRange, binCount );
				y1 = (int)((double)y+((double)bin)* hFactor+(double)heightPer);
				if( gapPrevX >= 0 )
					drawScaledBox(hvg, sampleX, gapPrevX, scale, 
					xOff, (int)y1, (int)(.10*heightPer), shadesOfGray[2]);
				gapPrevX = sampleX;
				prevX = -1; /*connect next point with gray bar too*/
				continue;
			}
			if (sampleY > maxRange)
				sampleY = maxRange;
			if (sampleY < minRange)
				sampleY = minRange;
			bin = -whichSampleBin( sampleY, minRange, maxRange, binCount );


			x1 = round((double)(sampleX-winStart)*scale) + xOff;
			y1 = (int)((double)y+((double)bin)* hFactor+(double)heightPer);



			if (prevX > 0)
			{
				y2 = prevY;
				x2 = round((double)(prevX-winStart)*scale) + xOff;
				if( wiggleType == wiggleLinearInterpolation ) 
					/*connect samples*/
				{
					if( lineGapSize < 0 || prevX - sampleX <= lineGapSize )   
						/*don't interpolate over large gaps*/
					{
						if (fill)
							hvGfxFillUnder(hvg, x1,y1, x2,y2, ybase, bColor);
						else
							hvGfxLine(hvg, x1,y1, x2,y2, color);
					}
				}
			}

			//if( x1 < 0 || x1 > tl.picWidth )
			//printf("x1 = %d, sampleX=%d, winStart = %d\n<br>", x1, sampleX, winStart );
			if( x1 >= 0 && x1 <= tl.picWidth )
			{
				/* Draw the points themselves*/
				drawScaledBox(hvg, sampleX, sampleX+1, scale, xOff, (int)y1-1, 3, color);
				if( fill )
					drawScaledBox(hvg, sampleX, sampleX+1, scale, xOff, (int)y1+2, 
					ybase-y1-2, bColor);
			}

			prevX = gapPrevX = sampleX;
			prevY = y1;
		}

		leftSide = max( tg->itemStart(tg,lf), winStart );
		rightSide = min(  tg->itemEnd(tg,lf), winEnd );

		currentX =  round((double)((int)leftSide-winStart)*scale) + xOff;
		currentXEnd =  round((double)((int)rightSide-winStart)*scale) + xOff;
		currentWidth = currentXEnd - currentX;

		if( noZoom && isFull )
		{
			fprintf(stderr, "mapBoxHc(id: %s;) in wiggleLinkedFeatures\n", 
				tg->track);
			mapBoxHc(hvg, lf->start, lf->end, currentX ,y, currentWidth,
				heightPer, tg->track, tg->mapItemName(tg, lf), tg->itemName(tg, lf));

			if( lf->next != NULL )
				y += sampleUpdateY( lf->name, lf->next->name, lineHeight );
			else
				y += lineHeight;
		}

	}
}
Example #7
0
static void vcfHapClusterDraw(struct track *tg, int seqStart, int seqEnd,
			      struct hvGfx *hvg, int xOff, int yOff, int width,
			      MgFont *font, Color color, enum trackVisibility vis)
/* Split samples' chromosomes (haplotypes), cluster them by center-weighted
 * alpha similarity, and draw in the order determined by clustering. */
{
struct vcfFile *vcff = tg->extraUiData;
if (vcff->records == NULL)
    return;
purple = hvGfxFindColorIx(hvg, 0x99, 0x00, 0xcc);
undefYellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
enum hapColorMode colorMode = getColorMode(tg->tdb);
pushWarnHandler(ignoreEm);
struct vcfRecord *rec;
for (rec = vcff->records;  rec != NULL;  rec = rec->next)
    vcfParseGenotypes(rec);
popWarnHandler();
unsigned short gtHapCount = 0;
int nRecords = slCount(vcff->records);
int centerIx = getCenterVariantIx(tg, seqStart, seqEnd, vcff->records);
// Limit the number of variants that we compare, to keep from timing out:
// (really what we should limit is the number of distinct haplo's passed to hacTree!)
// In the meantime, this should at least be a cart var...
int maxVariantsPerSide = 50;
int startIx = max(0, centerIx - maxVariantsPerSide);
int endIx = min(nRecords, centerIx+1 + maxVariantsPerSide);
struct hacTree *ht = NULL;
unsigned short *gtHapOrder = clusterHaps(vcff, centerIx, startIx, endIx, &gtHapCount, &ht);
struct vcfRecord *centerRec = NULL;
int ix;
// Unlike drawing order (last drawn is on top), the first mapBox gets priority,
// so map center variant before drawing & mapping other variants!
for (rec = vcff->records, ix=0;  rec != NULL;  rec = rec->next, ix++)
    {
    if (ix == centerIx)
	{
	centerRec = rec;
	mapBoxForCenterVariant(rec, hvg, tg, xOff, yOff, width);
	break;
	}
    }
for (rec = vcff->records, ix=0;  rec != NULL;  rec = rec->next, ix++)
    {
    boolean isClustered = (ix >= startIx && ix < endIx);
    if (ix != centerIx)
	drawOneRec(rec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, isClustered, FALSE,
		   colorMode);
    }
// Draw the center rec on top, outlined with black lines, to make sure it is very visible:
drawOneRec(centerRec, gtHapOrder, gtHapCount, tg, hvg, xOff, yOff, width, TRUE, TRUE,
	   colorMode);
// Draw as much of the tree as can fit in the left label area:
int extraPixel = (colorMode == altOnlyMode) ? 1 : 0;
int hapHeight = tg->height- CLIP_PAD - 2*extraPixel;
struct yFromNodeHelper yHelper = {0, NULL, NULL};
initYFromNodeHelper(&yHelper, yOff+extraPixel, hapHeight, gtHapCount, gtHapOrder,
		    vcff->genotypeCount);
struct titleHelper titleHelper = { NULL, 0, 0, 0, 0, NULL, NULL };
initTitleHelper(&titleHelper, tg->track, startIx, centerIx, endIx, nRecords, vcff);
char *treeAngle = cartOrTdbString(cart, tg->tdb, VCF_HAP_TREEANGLE_VAR, VCF_DEFAULT_HAP_TREEANGLE);
boolean drawRectangle = sameString(treeAngle, VCF_HAP_TREEANGLE_RECTANGLE);
drawTreeInLabelArea(ht, hvg, yOff+extraPixel, hapHeight+CLIP_PAD, &yHelper, &titleHelper,
		    drawRectangle);
}
Example #8
0
static void multiWigDraw(struct track *tg, int seqStart, int seqEnd,
        struct hvGfx *hvg, int xOff, int yOff, int width, 
        MgFont *font, Color color, enum trackVisibility vis)
/* Draw items in multiWig container. */
{
struct track *subtrack;
boolean errMsgShown = FALSE;
int y = yOff;
boolean errMsgFound = FALSE;
int numTracks = 0;
// determine if any subtracks had errors and count them up
for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack) )
	{
	numTracks++;
	if (subtrack->networkErrMsg)
	    errMsgFound = TRUE;
	}
    }

if (errMsgFound)
    {
    Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
    hvGfxBox(hvg, xOff, yOff, width, tg->height, yellow);
    }

struct wigCartOptions *wigCart = tg->wigCartData;
struct wigGraphOutput *wgo = setUpWgo(xOff, yOff, width, tg->height, numTracks, wigCart, hvg);

// we want to the order to be the same in all the modes 
if (wigCart->aggregateFunction == wiggleAggregateStacked)
    slReverse(&tg->subtracks);

/* Cope with autoScale and stacked bars - we do it here rather than in the child tracks, so that
 * all children can be on same scale. */
double minVal, maxVal;

/* Force load of all predraw arrays so can do calcs. Build up list, and then
 * figure out max/min.  No worries about multiple loading, the loaders protect
 * themselves. */
struct slRef *refList = NULL;
for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack))
	{
	struct preDrawContainer *pre = subtrack->loadPreDraw(subtrack, seqStart, seqEnd, width);

	if (pre != NULL)  // pre maybe null if the load fails
	    {
	    preDrawWindowFunction(pre->preDraw, pre->preDrawSize, wigCart->windowingFunction,
		    wigCart->transformFunc, wigCart->doNegative);
	    preDrawSmoothing(pre->preDraw, pre->preDrawSize, wigCart->smoothingWindow);
	    pre->smoothingDone = TRUE;
	    refAdd(&refList, pre);
	    }
	}
    }
slReverse(&refList);
minMaxVals(refList, &minVal, &maxVal, wigCart->windowingFunction,  wigCart->alwaysZero, wgo->yOffsets);
slFreeList(&refList);

if (!wigCart->autoScale)
    {
    minVal = wigCart->minY;
    maxVal = wigCart->maxY;
    }

/* Loop through again setting up the wigCarts of the children to have minY/maxY for
 * our limits and autoScale off. */
for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (!isSubtrackVisible(subtrack))
	continue;

    struct wigCartOptions *wigCart = subtrack->wigCartData;
    wigCart->minY = minVal;
    wigCart->maxY = maxVal;
    wigCart->autoScale = wiggleScaleManual;
    struct preDrawContainer *pre = subtrack->preDrawContainer;

    if (pre != NULL)  // pre maybe null if the load fails
	{
	pre->graphUpperLimit = maxVal;
	pre->graphLowerLimit = minVal;
	}
    }

int numTrack = 0;
for (subtrack = tg->subtracks; subtrack != NULL; subtrack = subtrack->next)
    {
    if (isSubtrackVisible(subtrack))
	{
        if (!subtrack->networkErrMsg || !errMsgShown)
	    {
	    if (subtrack->networkErrMsg)
	       errMsgShown = TRUE;
	    wgo->numTrack = numTrack++;
	    subtrack->wigGraphOutput = wgo;
	    int height = subtrack->totalHeight(subtrack, vis);
	    hvGfxSetClip(hvg, xOff, y, width, height);
	    if (wigCart->aggregateFunction != wiggleAggregateNone)
		subtrack->lineHeight = tg->lineHeight;
	    subtrack->drawItems(subtrack, seqStart, seqEnd, hvg, xOff, y, width, font, color, vis);
	    if (wigCart->aggregateFunction == wiggleAggregateNone)
		{
		y += height + 1;
		wgo->yOff = y;
		}
	    hvGfxUnclip(hvg);
	    }
	}
    }

if (wigCart->aggregateFunction == wiggleAggregateTransparent)
   {
   floatPicIntoHvg(wgo->image, xOff, yOff, hvg);
   floatPicFree((struct floatPic **)&wgo->image);
   }

char *url = trackUrl(tg->track, chromName);
mapBoxHgcOrHgGene(hvg, seqStart, seqEnd, xOff, yOff, width, tg->height, tg->track, tg->track, NULL,
	      url, TRUE, NULL);
}