void bamPairedDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a bam linked features series item at position. (like linkedFeaturesSeriesDrawAt, * but calls bamDrawAt instead of linkedFeaturesDrawAt) */ { struct linkedFeaturesSeries *lfs = item; struct linkedFeatures *lf; int midY = y + (tg->heightPer>>1); int prevEnd = lfs->start; if ((lf = lfs->features) == NULL) return; for (lf = lfs->features; lf != NULL; lf = lf->next) { int x1 = round((double)((int)prevEnd-winStart)*scale) + xOff; int x2 = round((double)((int)lf->start-winStart)*scale) + xOff; int w = x2-x1; if (w > 0) hvGfxLine(hvg, x1, midY, x2, midY, color); bamDrawAt(tg, lf, hvg, xOff, y, scale, font, color, vis); prevEnd = lf->end; } }
void cytoBandIdeoDraw(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 entire chromosome with a little red box around our current position. */ { double scale = 0; int xBorder = 4; int x1, x2; int yBorder = 0; int chromSize = hChromSize(database, chromName); struct cytoBand *cbList = NULL, *cb = NULL; scale = (double) (width - (2 * xBorder)) / chromSize; /* Subtrack 10 for the 5 pixels buffer on either side. */ tg->heightPer -= 11; tg->lineHeight -= 11; /* Time to draw the bands. */ hvGfxSetClip(hvg, xOff, yOff, width, tg->height); genericDrawItems(tg, 0, chromSize, hvg, xOff+xBorder, yOff+5, width-(2*xBorder), font, color, tvDense); x1 = round((winStart)*scale) + xOff + xBorder -1; x2 = round((winEnd)*scale) + xOff + xBorder -1; if(x1 >= x2) x2 = x1+1; yBorder = tg->heightPer + 7 + 1; /* Draw an outline around chromosome for visualization purposes. Helps to make the chromosome look better. */ hvGfxLine(hvg, xOff+xBorder, yOff+4, xOff+width-xBorder, yOff+4, MG_BLACK); hvGfxLine(hvg, xOff+xBorder, yOff+yBorder-3, xOff+width-xBorder, yOff+yBorder-3, MG_BLACK); hvGfxLine(hvg, xOff+xBorder, yOff+4, xOff+xBorder, yOff+yBorder-3, MG_BLACK); hvGfxLine(hvg, xOff+width-xBorder, yOff+4, xOff+width-xBorder, yOff+yBorder-3, MG_BLACK); /* Find and draw the centromere which is defined as the two bands with gieStain "acen" */ cbList = tg->items; for(cb = cbList; cb != NULL; cb = cb->next) { /* If centromere do some drawing. */ if(sameString(cb->gieStain, "acen")) { int cenLeft, cenRight, cenTop, cenBottom; /* Get the coordinates of the edges of the centromere. */ cenLeft = round((cb->chromStart)*scale) + xOff + xBorder; cenRight = round((cb->next->chromEnd)*scale) + xOff + xBorder; cenTop = yOff+4; cenBottom = yOff + yBorder - 3; /* Draw centromere itself. */ hCytoBandDrawCentromere(hvg, cenLeft, cenTop, cenRight - cenLeft, cenBottom-cenTop+1, MG_WHITE, hCytoBandCentromereColor(hvg)); break; } } /* Draw a red box around all positions in windows for this chromName. * Double thick so two pixels thick each. */ struct window *window; for (window=windows; window; window=window->next) { if (!sameString(chromName, window->chromName)) continue; x1 = round((window->winStart)*scale) + xOff + xBorder -1; x2 = round((window->winEnd)*scale) + xOff + xBorder -1; hvGfxBox(hvg, x1, yOff+1, x2-x1, 2, MG_RED); hvGfxBox(hvg, x1, yOff + yBorder - 1, x2-x1, 2, MG_RED); hvGfxBox(hvg, x1, yOff+1, 2, yBorder, MG_RED); hvGfxBox(hvg, x2, yOff+1, 2, yBorder, MG_RED); } hvGfxUnclip(hvg); /* Put back the lineHeight for the track now that we are done spoofing tgDrawItems(). */ tg->heightPer += 11; tg->lineHeight += 11; }
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; } } }
static void altGraphXDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int yOff, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw an altGraphX at the specified location. */ { int i = 0; int s =0, e=0; int heightPer = tg->heightPer; int start = 0, end = 0; struct altGraphX *ag = item; int width = 0; int x1, x2; /* Create a link to hgc. */ if(tg->mapsSelf && tg->mapItem) { char name[256]; int nameWidth = 0; int textX = 0; start = max(winStart, ag->tStart); end = min(winEnd, ag->tEnd); width = (end - start) * scale; x1 = round((double)((int) start - winStart)*scale) + xOff; textX = x1; if(width == 0) width = 1; /* If there isn't enough room on before the left edge snap the label to the left edge. */ if(withLeftLabels && tg->limitedVis == tvPack) { safef(name, sizeof(name), "%s", tg->itemName(tg, ag)); nameWidth = mgFontStringWidth(font, name); textX = textX - (nameWidth + tl.nWidth/2); if(textX < insideX) textX = insideX - nameWidth; width = width + (x1 - textX); } tg->mapItem(tg, hvg, ag, "notUsed", "notUsed", ag->tStart, ag->tEnd, textX, yOff, width, heightPer); } /* Draw the edges (exons and introns). */ for(i= 0; i < ag->edgeCount; i++) { Color color2; s = ag->vPositions[ag->edgeStarts[i]]; e = ag->vPositions[ag->edgeEnds[i]]; color2 = MG_BLACK; /* If you want to shade by number of transcripts uncomment next line. */ /* color2 = altGraphXColorForEdge(hvg, ag, i); */ if(isExon(ag, i)) { if(vis == tvPack) drawScaledBox(hvg, s, e, scale, xOff, yOff+heightPer/2, heightPer/2, color2); else drawScaledBox(hvg, s, e, scale, xOff, yOff, heightPer, color2); } else { int midX; s = ag->vPositions[ag->edgeStarts[i]]; e = ag->vPositions[ag->edgeEnds[i]]; x1 = round((double)((int) s - winStart)*scale) + xOff; x2 = round((double)((int) e - winStart)*scale) + xOff; if(vis == tvPack) { midX = (x1+x2)/2; hvGfxLine(hvg, x1, yOff+heightPer/2, midX, yOff, color2); hvGfxLine(hvg, midX, yOff, x2, yOff+heightPer/2, color2); } else hvGfxLine(hvg, x1, yOff+heightPer/2, x2, yOff+heightPer/2, color2); } } }
static int rDrawTreeInLabelArea(struct hacTree *ht, struct hvGfx *hvg, enum yRetType yType, int x, yFromNodeFunc *yFromNode, void *yh, struct titleHelper *th, boolean drawRectangle) /* Recursively draw the haplotype clustering tree in the left label area. * Returns pixel height for use at non-leaf levels of tree. */ { const int branchW = 4; int labelEnd = leftLabelX + leftLabelWidth; if (yType == yrtStart || yType == yrtEnd) { // We're just getting vertical span of a leaf cluster, not drawing any lines. int yLeft, yRight; if (ht->left) yLeft = rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th, drawRectangle); else yLeft = yFromNode(ht->itemOrCluster, yh, yType); if (ht->right) yRight = rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th, drawRectangle); else yRight = yFromNode(ht->itemOrCluster, yh, yType); if (yType == yrtStart) return min(yLeft, yRight); else return max(yLeft, yRight); } // Otherwise yType is yrtMidPoint. If we have 2 children, we'll be drawing some lines: if (ht->left != NULL && ht->right != NULL) { int midY; if (ht->childDistance == 0 || x+(2*branchW) > labelEnd) { // Treat this as a leaf cluster. // Recursing twice is wasteful. Could be avoided if this, and yFromNode, // returned both yStart and yEnd. However, the time to draw a tree of // 2188 hap's (1kG phase1 interim) is in the noise, so I consider it // not worth the effort of refactoring to save a sub-millisecond here. int yStartLeft = rDrawTreeInLabelArea(ht->left, hvg, yrtStart, x+branchW, yFromNode, yh, th, drawRectangle); int yEndLeft = rDrawTreeInLabelArea(ht->left, hvg, yrtEnd, x+branchW, yFromNode, yh, th, drawRectangle); int yStartRight = rDrawTreeInLabelArea(ht->right, hvg, yrtStart, x+branchW, yFromNode, yh, th, drawRectangle); int yEndRight = rDrawTreeInLabelArea(ht->right, hvg, yrtEnd, x+branchW, yFromNode, yh, th, drawRectangle); int yStart = min(yStartLeft, yStartRight); int yEnd = max(yEndLeft, yEndRight); midY = (yStart + yEnd) / 2; Color col = (ht->childDistance == 0) ? purple : MG_BLACK; if (drawRectangle || ht->childDistance != 0) { hvGfxLine(hvg, x+branchW, yStart, x+branchW, yEnd-1, col); hvGfxLine(hvg, x+branchW, yStart, labelEnd, yStart, col); hvGfxLine(hvg, x+branchW, yEnd-1, labelEnd, yEnd-1, col); } else { hvGfxLine(hvg, x, midY, x+1, midY, col); hvGfxLine(hvg, x+1, midY, labelEnd-1, yStart, col); hvGfxLine(hvg, x+1, midY, labelEnd-1, yEnd-1, col); } addClusterMapItem(ht, x, yStart, labelEnd, yEnd-1, th); } else { int leftMid = rDrawTreeInLabelArea(ht->left, hvg, yrtMidPoint, x+branchW, yFromNode, yh, th, drawRectangle); int rightMid = rDrawTreeInLabelArea(ht->right, hvg, yrtMidPoint, x+branchW, yFromNode, yh, th, drawRectangle); midY = (leftMid + rightMid) / 2; hvGfxLine(hvg, x+branchW, leftMid, x+branchW, rightMid, MG_BLACK); addClusterMapItem(ht, x, min(leftMid, rightMid), x+branchW-1, max(leftMid, rightMid), th); } if (drawRectangle || ht->childDistance != 0) hvGfxLine(hvg, x, midY, x+branchW, midY, MG_BLACK); return midY; } else if (ht->left != NULL) return rDrawTreeInLabelArea(ht->left, hvg, yType, x, yFromNode, yh, th, drawRectangle); else if (ht->right != NULL) return rDrawTreeInLabelArea(ht->right, hvg, yType, x, yFromNode, yh, th, drawRectangle); // Leaf node -- return pixel height. Draw a line if yType is midpoint. int y = yFromNode(ht->itemOrCluster, yh, yType); if (yType == yrtMidPoint && x < labelEnd) { hvGfxLine(hvg, x, y, labelEnd, y, purple); addClusterMapItem(ht, x, y, labelEnd, y+1, th); } return y; }
static void drawOneRec(struct vcfRecord *rec, unsigned short *gtHapOrder, unsigned short gtHapCount, struct track *tg, struct hvGfx *hvg, int xOff, int yOff, int width, boolean isClustered, boolean isCenter, enum hapColorMode colorMode) /* Draw a stack of genotype bars for this record */ { unsigned int chromStartMap = vcfRecordTrimIndelLeftBase(rec); unsigned int chromEndMap = vcfRecordTrimAllelesRight(rec); const double scale = scaleForPixels(width); int x1 = round((double)(rec->chromStart-winStart)*scale) + xOff; int x2 = round((double)(rec->chromEnd-winStart)*scale) + xOff; int w = x2-x1; if (w <= 1) { x1--; w = 3; } // When coloring mode is altOnly, we draw one extra pixel row at the top & one at bottom // to show the locations of variants, since the reference alleles are invisible: int extraPixel = 0; int hapHeight = tg->height - CLIP_PAD; if (colorMode == altOnlyMode) { hvGfxLine(hvg, x1, yOff, x2, yOff, (isClustered ? purple : shadesOfGray[5])); extraPixel = 1; hapHeight -= extraPixel*2; } double hapsPerPix = (double)gtHapCount / hapHeight; int pixIx; for (pixIx = 0; pixIx < hapHeight; pixIx++) { int gtHapOrderIxStart = (int)(hapsPerPix * pixIx); int gtHapOrderIxEnd = round(hapsPerPix * (pixIx + 1)); if (gtHapOrderIxEnd == gtHapOrderIxStart) gtHapOrderIxEnd++; int unks = 0, refs = 0, alts = 0; int gtHapOrderIx; for (gtHapOrderIx = gtHapOrderIxStart; gtHapOrderIx < gtHapOrderIxEnd; gtHapOrderIx++) { int gtHapIx = gtHapOrder[gtHapOrderIx]; int hapIx = gtHapIx & 1; int gtIx = gtHapIx >>1; struct vcfGenotype *gt = &(rec->genotypes[gtIx]); if (gt->isPhased || gt->isHaploid || (gt->hapIxA == gt->hapIxB)) { int alIx = hapIx ? gt->hapIxB : gt->hapIxA; if (alIx < 0) unks++; else if (alIx > 0) alts++; else refs++; } else unks++; } int y = yOff + extraPixel + pixIx; Color col; if (colorMode == baseMode) col = colorByBase(refs, alts, unks, rec->alleles[0], rec->alleles[1]); else if (colorMode == refAltMode) col = colorByRefAlt(refs, alts, unks); else col = colorByAltOnly(refs, alts, unks); if (col != MG_WHITE) hvGfxLine(hvg, x1, y, x2, y, col); } int yBot = yOff + tg->height - CLIP_PAD - 1; if (isCenter) { if (colorMode == altOnlyMode) { // Colorful outline to distinguish this variant: hvGfxLine(hvg, x1-1, yOff, x1-1, yBot, purple); hvGfxLine(hvg, x2+1, yOff, x2+1, yBot, purple); hvGfxLine(hvg, x1-1, yOff, x2+1, yOff, purple); hvGfxLine(hvg, x1-1, yBot, x2+1, yBot, purple); } else { // Thick black lines to distinguish this variant: hvGfxBox(hvg, x1-3, yOff, 3, tg->height, MG_BLACK); hvGfxBox(hvg, x2, yOff, 3, tg->height, MG_BLACK); hvGfxLine(hvg, x1-2, yOff, x2+2, yOff, MG_BLACK); hvGfxLine(hvg, x1-2, yBot, x2+2, yBot, MG_BLACK); } // Mouseover was handled already by mapBoxForCenterVariant } else { struct dyString *dy = dyStringNew(0); gtSummaryString(rec, dy); mapBoxHgcOrHgGene(hvg, chromStartMap, chromEndMap, x1, yOff, w, tg->height, tg->track, rec->name, dy->string, NULL, TRUE, NULL); } if (colorMode == altOnlyMode) hvGfxLine(hvg, x1, yBot, x2, yBot, (isClustered ? purple : shadesOfGray[5])); }
static void longRangeDraw(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 list of longTabix structures. */ { double scale = scaleForWindow(width, seqStart, seqEnd); struct bed *beds = tg->items; unsigned int maxWidth; struct longRange *longRange; char buffer[1024]; char itemBuf[2048]; char statusBuf[2048]; safef(buffer, sizeof buffer, "%s.%s", tg->tdb->track, LONG_MINSCORE); double minScore = sqlDouble(cartUsualString(cart, buffer, LONG_DEFMINSCORE)); struct longRange *longRangeList = parseLongTabix(beds, &maxWidth, minScore); for(longRange=longRangeList; longRange; longRange=longRange->next) { safef(itemBuf, sizeof itemBuf, "%d", longRange->id); safef(statusBuf, sizeof statusBuf, "%g %s:%d %s:%d", longRange->score, longRange->sChrom, longRange->s, longRange->eChrom, longRange->e); boolean sOnScreen = (longRange->s >= seqStart) && (longRange->s < seqEnd); unsigned sx = 0, ex = 0; if (sOnScreen) sx = (longRange->s - seqStart) * scale + xOff; if (differentString(longRange->sChrom, longRange->eChrom)) { if (!sOnScreen) continue; // draw the foot int footWidth = scale * (longRange->sw / 2); hvGfxLine(hvg, sx - footWidth, yOff, sx + footWidth, yOff, MG_BLUE); int height = tg->height/2; if (tg->visibility == tvDense) height = tg->height; unsigned yPos = yOff + height; hvGfxLine(hvg, sx, yOff, sx, yPos, MG_BLUE); if (tg->visibility == tvFull) { mapBoxHgcOrHgGene(hvg, longRange->s, longRange->s, sx - 2, yOff, 4, tg->height/2, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL); safef(buffer, sizeof buffer, "%s:%d", longRange->eChrom, longRange->e); hvGfxTextCentered(hvg, sx, yPos + 2, 4, 4, MG_BLUE, font, buffer); int width = vgGetFontStringWidth(hvg->vg, font, buffer); int height = vgGetFontPixelHeight(hvg->vg, font); mapBoxHgcOrHgGene(hvg, longRange->s, longRange->s, sx - width/2, yPos, width, height, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL); } } else { boolean eOnScreen = (longRange->e >= seqStart) && (longRange->e < seqEnd); if (!(sOnScreen || eOnScreen)) continue; if (eOnScreen) ex = (longRange->e - seqStart) * scale + xOff; double longRangeWidth = longRange->e - longRange->s; int peak = (tg->height - 15) * ((double)longRangeWidth / maxWidth) + yOff + 10; if (tg->visibility == tvDense) peak = yOff + tg->height; if (sOnScreen) { int footWidth = scale * (longRange->sw / 2); hvGfxLine(hvg, sx - footWidth, yOff, sx + footWidth, yOff, color); hvGfxLine(hvg, sx, yOff, sx, peak, color); } if (eOnScreen) { int footWidth = scale * (longRange->ew / 2); hvGfxLine(hvg, ex - footWidth, yOff, ex + footWidth, yOff, color); hvGfxLine(hvg, ex, yOff, ex, peak, color); } if (tg->visibility == tvFull) { unsigned sPeak = sOnScreen ? sx : xOff; unsigned ePeak = eOnScreen ? ex : xOff + width; hvGfxLine(hvg, sPeak, peak, ePeak, peak, color); safef(statusBuf, sizeof statusBuf, "%g %s:%d %s:%d", longRange->score, longRange->sChrom, longRange->s, longRange->eChrom, longRange->e); if (sOnScreen) mapBoxHgcOrHgGene(hvg, longRange->s, longRange->e, sx - 2, yOff, 4, peak - yOff, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL); if (eOnScreen) mapBoxHgcOrHgGene(hvg, longRange->s, longRange->e, ex - 2, yOff, 4, peak - yOff, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL); mapBoxHgcOrHgGene(hvg, longRange->s, longRange->e, sPeak, peak-2, ePeak - sPeak, 4, tg->track, itemBuf, statusBuf, NULL, TRUE, NULL); } } } }