8a0946dd6870f10cde056ba243f1fb4ec1fd16b4 angie Thu Feb 27 11:58:33 2014 -0800 Adding support for plain VCF custom tracks (as opposed to VCF+tabix),since users seem to want to upload VCF, and as long as the file is not too big it will work OK. This means adding a new track type vcf (as opposed to vcfTabix) and supporting it in hgTracks, hgTrackUi, hgc, hgTables and hgVai. (and others I've forgotten?) refs #12416 diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c index 15f50ad..dd9d086 100644 --- src/hg/hgTracks/vcfTrack.c +++ src/hg/hgTracks/vcfTrack.c @@ -1,35 +1,29 @@ /* vcfTrack -- handlers for Variant Call Format data. */ #include "common.h" #include "bigWarn.h" #include "dystring.h" #include "errCatch.h" #include "hacTree.h" #include "hdb.h" #include "hgColors.h" #include "hgTracks.h" #include "pgSnp.h" #include "trashDir.h" #include "vcf.h" #include "vcfUi.h" -#if (defined USE_TABIX && defined KNETFILE_HOOKS) -#include "knetUdc.h" -#include "udc.h" -#endif//def USE_TABIX && KNETFILE_HOOKS - -#ifdef USE_TABIX static boolean getMinQual(struct trackDb *tdb, double *retMinQual) /* Return TRUE and set retMinQual if cart contains minimum QUAL filter */ { if (cartUsualBooleanClosestToHome(cart, tdb, FALSE, VCF_APPLY_MIN_QUAL_VAR, VCF_DEFAULT_APPLY_MIN_QUAL)) { if (retMinQual != NULL) *retMinQual = cartUsualDoubleClosestToHome(cart, tdb, FALSE, VCF_MIN_QUAL_VAR, VCF_DEFAULT_MIN_QUAL); return TRUE; } return FALSE; } @@ -1109,30 +1103,47 @@ * this to overwrite the methods for the rest of execution: */ { tg->heightPer = (tg->visibility == tvSquish) ? (tl.fontHeight/4) : (tl.fontHeight / 2); tg->lineHeight = tg->heightPer + 1; tg->drawItems = vcfHapClusterDraw; tg->totalHeight = vcfHapClusterTotalHeight; tg->itemHeight = tgFixedItemHeight; tg->itemName = vcfHapClusterTrackName; tg->mapItemName = vcfHapClusterTrackName; tg->itemStart = tgItemNoStart; tg->itemEnd = tgItemNoEnd; tg->mapsSelf = TRUE; tg->extraUiData = vcff; } +static void indelTweakMapItem(struct track *tg, struct hvGfx *hvg, void *item, + char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) +/* Pass the original vcf chromStart to pgSnpMapItem, so if we have trimmed an identical + * first base from item's alleles and start, we will still pass the correct start to hgc. */ +{ +struct pgSnpVcfStart *psvs = item; +pgSnpMapItem(tg, hvg, item, itemName, mapItemName, psvs->vcfStart, end, x, y, width, height); +} + + +#ifdef USE_TABIX + +#ifdef KNETFILE_HOOKS +#include "knetUdc.h" +#include "udc.h" +#endif//def KNETFILE_HOOKS + static void vcfTabixLoadItems(struct track *tg) /* Load items in window from VCF file using its tabix index file. */ { char *fileOrUrl = NULL; /* Figure out url or file name. */ if (tg->parallelLoading) { /* do not use mysql during parallel-fetch load */ fileOrUrl = trackDbSetting(tg->tdb, "bigDataUrl"); } else { struct sqlConnection *conn = hAllocConnTrack(database, tg->tdb); fileOrUrl = bbiNameFromSettingOrTableChrom(tg->tdb, conn, tg->table, chromName); hFreeConn(&conn); @@ -1162,39 +1173,30 @@ } // Don't vcfFileFree here -- we are using its string pointers! } } errCatchEnd(errCatch); if (errCatch->gotError || vcff == NULL) { if (isNotEmpty(errCatch->message->string)) tg->networkErrMsg = cloneString(errCatch->message->string); tg->drawItems = bigDrawWarning; tg->totalHeight = bigWarnTotalHeight; } errCatchFree(&errCatch); } -static void indelTweakMapItem(struct track *tg, struct hvGfx *hvg, void *item, - char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) -/* Pass the original vcf chromStart to pgSnpMapItem, so if we have trimmed an identical - * first base from item's alleles and start, we will still pass the correct start to hgc. */ -{ -struct pgSnpVcfStart *psvs = item; -pgSnpMapItem(tg, hvg, item, itemName, mapItemName, psvs->vcfStart, end, x, y, width, height); -} - void vcfTabixMethods(struct track *track) /* Methods for VCF + tabix files. */ { #ifdef KNETFILE_HOOKS knetUdcInstall(); #endif pgSnpMethods(track); track->mapItem = indelTweakMapItem; // Disinherit next/prev flag and methods since we don't support next/prev: track->nextExonButtonable = FALSE; track->nextPrevExon = NULL; track->nextPrevItem = NULL; track->loadItems = vcfTabixLoadItems; track->canPack = TRUE; } @@ -1214,15 +1216,78 @@ "Get tabix from samtools.sourceforge.net and recompile kent/src with USE_TABIX=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); } void vcfTabixMethods(struct track *track) /* Methods for VCF alignment files, in absence of tabix lib. */ { // NOP warning method to warn users that tabix is not installed. messageLineMethods(track); track->drawItems = drawUseVcfTabixWarning; } #endif // no USE_TABIX + +static void vcfLoadItems(struct track *tg) +/* Load items in window from VCF file. */ +{ +int vcfMaxErr = -1; +struct vcfFile *vcff = NULL; +boolean hapClustEnabled = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, + VCF_HAP_ENABLED_VAR, TRUE); +char *table = tg->table; +struct customTrack *ct = tg->customPt; +struct sqlConnection *conn; +if (ct == NULL) + conn = hAllocConnTrack(database, tg->tdb); +else + { + conn = hAllocConn(CUSTOM_TRASH); + table = ct->dbTableName; + } +char *vcfFile = bbiNameFromSettingOrTable(tg->tdb, conn, table); +hFreeConn(&conn); +/* protect against parse error */ +struct errCatch *errCatch = errCatchNew(); +if (errCatchStart(errCatch)) + { + vcff = vcfFileMayOpen(vcfFile, chromName, winStart, winEnd, vcfMaxErr, -1, TRUE); + if (vcff != NULL) + { + filterRecords(vcff, tg->tdb); + if (hapClustEnabled && vcff->genotypeCount > 1 && vcff->genotypeCount < 3000 && + (tg->visibility == tvPack || tg->visibility == tvSquish)) + vcfHapClusterOverloadMethods(tg, vcff); + else + { + tg->items = vcfFileToPgSnp(vcff, tg->tdb); + // pgSnp bases coloring/display decision on count of items: + tg->customInt = slCount(tg->items); + } + // Don't vcfFileFree here -- we are using its string pointers! + } + } +errCatchEnd(errCatch); +if (errCatch->gotError || vcff == NULL) + { + if (isNotEmpty(errCatch->message->string)) + tg->networkErrMsg = cloneString(errCatch->message->string); + tg->drawItems = bigDrawWarning; + tg->totalHeight = bigWarnTotalHeight; + } +errCatchFree(&errCatch); +} + +void vcfMethods(struct track *track) +/* Methods for Variant Call Format. */ +{ +pgSnpMethods(track); +track->mapItem = indelTweakMapItem; +// Disinherit next/prev flag and methods since we don't support next/prev: +track->nextExonButtonable = FALSE; +track->nextPrevExon = NULL; +track->nextPrevItem = NULL; +track->loadItems = vcfLoadItems; +track->canPack = TRUE; +}