820ebcf85a344a03cf2279b6ceee42a25514f4a3 angie Mon May 23 09:41:50 2011 -0700 Feature #3711 (VCF haplotype clustering): User can select which variantis used as the center (for center-weighted clustering) by clicking on a link in its details page. diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c index 036741b..420ade8 100644 --- src/hg/hgTracks/vcfTrack.c +++ src/hg/hgTracks/vcfTrack.c @@ -316,35 +316,30 @@ { if (grayUnphasedHet && !gt->isPhased && gt->hapIxA != gt->hapIxB) return shadesOfGray[5]; int alIx = hapIx ? gt->hapIxB : gt->hapIxA; return alIx ? MG_RED : MG_BLUE; } INLINE int drawOneHap(struct vcfGenotype *gt, int hapIx, char *ref, char *altAlleles[], int altCount, struct hvGfx *hvg, int x1, int y, int w, int itemHeight, int lineHeight) /* Draw a base-colored box for genotype[hapIx]. Return the new y offset. */ { Color color = colorHapByRefAlt ? colorFromRefAlt(gt, hapIx, TRUE) : colorFromGt(gt, hapIx, ref, altAlleles, altCount, TRUE); -if (w == 1) - { - x1--; - w = 3; - } hvGfxBox(hvg, x1, y, w, itemHeight+1, color); y += itemHeight+1; return y; } INLINE char *gtSummaryString(struct vcfRecord *rec, char **altAlleles, int altCount) // Make pgSnp-like mouseover text, but with genotype counts instead of allele counts. // NOTE 1: Returned string is statically allocated, don't free it! // NOTE 2: if revCmplDisp is set, this reverse-complements rec->ref and altAlleles! { static struct dyString *dy = NULL; if (dy == NULL) dy = dyStringNew(0); dyStringClear(dy); const struct vcfFile *vcff = rec->file; @@ -380,64 +375,99 @@ static void drawOneRec(struct vcfRecord *rec, unsigned short *gtHapOrder, int gtHapEnd, struct track *tg, struct hvGfx *hvg, int xOff, int yOff, int width) /* Draw a stack of genotype bars for this record */ { static struct dyString *tmp = NULL; if (tmp == NULL) tmp = dyStringNew(0); char *altAlleles[256]; int altCount; const int lineHeight = tg->lineHeight; const int itemHeight = tg->heightPer; 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) - w = 1; +if (w <= 1) + { + x1--; + w = 3; + } int y = yOff; dyStringClear(tmp); dyStringAppend(tmp, rec->alt); altCount = chopCommas(tmp->string, altAlleles); int gtHapOrderIx; for (gtHapOrderIx = 0; gtHapOrderIx < gtHapEnd; gtHapOrderIx++) { int gtHapIx = gtHapOrder[gtHapOrderIx]; int hapIx = gtHapIx & 1; int gtIx = gtHapIx >>1; struct vcfGenotype *gt = &(rec->genotypes[gtIx]); y = drawOneHap(gt, hapIx, rec->ref, altAlleles, altCount, hvg, x1, y, w, itemHeight, lineHeight); } mapBoxHgcOrHgGene(hvg, rec->chromStart, rec->chromEnd, x1, yOff, w, tg->height, tg->track, rec->name, gtSummaryString(rec, altAlleles, altCount), NULL, TRUE, NULL); } +static int getCenterVariantIx(struct track *tg, int seqStart, int seqEnd, + struct vcfRecord *records) +// If the user hasn't specified a local variant/position to use as center, +// just use the median variant in window. +{ +int defaultIx = (slCount(records)-1) / 2; +char cartVar[512]; +safef(cartVar, sizeof(cartVar), "%s.centerVariantPos", tg->tdb->track); +char *centerPos = cartOptionalString(cart, cartVar); +if (centerPos != NULL) + { + char *words[3]; + int wordCount = chopByChar(cloneString(centerPos), ':', words, sizeof(words)); + if (wordCount != 2) + errAbort("Cart variable %s format error: expected 'chrom:pos', got %s", + cartVar, centerPos); + if (sameString(chromName, words[0])) + { + int pos = sqlUnsigned(words[1]); + int winSize = seqEnd - seqStart; + if (pos > (seqStart - winSize) && pos < (seqEnd + winSize)) + { + int i; + struct vcfRecord *rec; + for (rec = records, i = 0; rec != NULL; rec = rec->next, i++) + if (rec->chromStart >= pos) + return i; + return i-1; + } + } + } +return defaultIx; +} + 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. */ { const struct vcfFile *vcff = tg->extraUiData; if (vcff->records == NULL) return; unsigned short gtHapEnd = 0; -// Use the median variant in the window as the center; would be even nicer to allow -// the user to choose a variant (or position) to use as center: -int ix, centerIx = (slCount(vcff->records)-1) / 2; +int ix, centerIx = getCenterVariantIx(tg, seqStart, seqEnd, vcff->records); unsigned short *gtHapOrder = clusterChroms(vcff, centerIx, >HapEnd); struct vcfRecord *rec, *centerRec = NULL; for (rec = vcff->records, ix=0; rec != NULL; rec = rec->next, ix++) { drawOneRec(rec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width); if (ix == centerIx) centerRec = rec; } // Draw the center rec on top, outlined with black lines, to make sure it is very visible: drawOneRec(centerRec, gtHapOrder, gtHapEnd, tg, hvg, xOff, yOff, width); const double scale = scaleForPixels(width); int x1 = round((double)(centerRec->chromStart-winStart)*scale) + xOff; int x2 = round((double)(centerRec->chromEnd-winStart)*scale) + xOff; int yBot = yOff + tg->height - 2; hvGfxBox(hvg, x1-4, yOff, 3, tg->height, color);