09208616b0f709b570f16ac1ed337a7b0c4353ef braney Sun Nov 1 15:33:40 2015 -0800 add bigChain support in hgTracks (no redmine) diff --git src/hg/hgTracks/chainTrack.c src/hg/hgTracks/chainTrack.c index 4e23083..b11f1ed 100644 --- src/hg/hgTracks/chainTrack.c +++ src/hg/hgTracks/chainTrack.c @@ -5,48 +5,100 @@ /* Copyright (C) 2013 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "hash.h" #include "localmem.h" #include "linefile.h" #include "jksql.h" #include "hdb.h" #include "hgTracks.h" #include "chainBlock.h" #include "chainLink.h" #include "chainDb.h" #include "chainCart.h" #include "hgColors.h" +#include "hubConnect.h" struct cartOptions { enum chainColorEnum chainColor; /* ChromColors, ScoreColors, NoColors */ int scoreFilter ; /* filter chains by score if > 0 */ }; -static void doQuery(struct sqlConnection *conn, char *fullName, +struct sqlClosure +{ +struct sqlConnection *conn; +}; + +struct bbClosure +{ +struct bbiFile *bbi; +}; + +typedef void (*linkRetrieveFunc)(void *closure, char *fullName, + struct lm *lm, struct hash *hash, + int start, int end, char * chainId, boolean isSplit); + +static void doBbQuery(void *closure, char *fullName, + struct lm *lm, struct hash *hash, + int start, int end, char * chainId, boolean isSplit) +/* doBbQuery- check a bigBed for chain elements between + * start and end. Use the passed hash to resolve chain + * id's and place the elements into the right + * linkedFeatures structure + */ +{ +struct bbClosure *bbClosure = (struct bbClosure *)closure; +struct bbiFile *bbi = bbClosure->bbi; +struct linkedFeatures *lf; +struct simpleFeature *sf; + +struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chromName, start, end, 0, lm); +char *bedRow[5]; +char startBuf[16], endBuf[16]; + +for (bb = bbList; bb != NULL; bb = bb->next) + { + bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); + lf = hashFindVal(hash, bedRow[3]); + + if (lf != NULL) + { + lmAllocVar(lm, sf); + sf->start = sqlUnsigned(bedRow[1]); + sf->end = sqlUnsigned(bedRow[2]); + sf->qStart = sqlUnsigned(bedRow[4]); + sf->qEnd = sf->qStart + (sf->end - sf->start); + slAddHead(&lf->components, sf); + } + } +} + +static void doQuery(void *closure, char *fullName, struct lm *lm, struct hash *hash, int start, int end, char * chainId, boolean isSplit) /* doQuery- check the database for chain elements between * start and end. Use the passed hash to resolve chain * id's and place the elements into the right * linkedFeatures structure */ { +struct sqlClosure *sqlClosure = (struct sqlClosure *)closure; +struct sqlConnection *conn = sqlClosure->conn; struct sqlResult *sr = NULL; char **row; struct linkedFeatures *lf; struct simpleFeature *sf; struct dyString *query = newDyString(1024); char *force = ""; if (isSplit) force = "force index (bin)"; if (chainId == NULL) sqlDyStringPrintf(query, "select chainId,tStart,tEnd,qStart from %sLink %-s where ", fullName, force); else @@ -77,44 +129,62 @@ sqlFreeResult(&sr); dyStringFree(&query); } static void chainDraw(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw chained features. This loads up the simple features from * the chainLink table, calls linkedFeaturesDraw, and then * frees the simple features again. */ { struct linkedFeatures *lf; struct simpleFeature *sf; struct lm *lm; struct hash *hash; /* Hash of chain ids. */ -struct sqlConnection *conn; +struct sqlConnection *conn = NULL; double scale = ((double)(winEnd - winStart))/width; char fullName[64]; int start, end, extra; struct simpleFeature *lastSf = NULL; int maxOverLeft = 0, maxOverRight = 0; int overLeft, overRight; if (tg->items == NULL) /*Exit Early if nothing to do */ return; +void *closure; +struct sqlClosure sqlClosure; +struct bbClosure bbClosure; +linkRetrieveFunc queryFunc; +if (tg->isBigBed) + { + closure = &bbClosure; + queryFunc = doBbQuery; + char *fileName = trackDbSetting(tg->tdb, "linkDataUrl"); + struct bbiFile *bbi = bigBedFileOpen(fileName); + bbClosure.bbi = bbi; + } +else + { + closure = &sqlClosure; + queryFunc = doQuery; + sqlClosure.conn = hAllocConn(database); + } + lm = lmInit(1024*4); hash = newHash(0); -conn = hAllocConn(database); /* Make up a hash of all linked features keyed by * id, which is held in the extras field. To * avoid burning memory on full chromosome views * we'll just make a single simple feature and * exclude from hash chains less than three pixels wide, * since these would always appear solid. */ for (lf = tg->items; lf != NULL; lf = lf->next) { double pixelWidth = (lf->end - lf->start) / scale; if (pixelWidth >= 2.5) { hashAdd(hash, lf->extra, lf); overRight = lf->end - seqEnd; if (overRight > maxOverRight) @@ -127,75 +197,75 @@ { lmAllocVar(lm, sf); sf->start = lf->start; sf->end = lf->end; sf->grayIx = lf->grayIx; lf->components = sf; } } /* if some chains are bigger than 3 pixels */ if (hash->size) { boolean isSplit = TRUE; /* Make up range query. */ safef(fullName, sizeof fullName, "%s_%s", chromName, tg->table); - if (!hTableExists(database, fullName)) + if (isHubTrack(tg->table) || !hTableExists(database, fullName)) { strcpy(fullName, tg->table); isSplit = FALSE; } /* in dense mode we don't draw the lines * so we don't need items off the screen */ if (vis == tvDense) - doQuery(conn, fullName, lm, hash, seqStart, seqEnd, NULL, isSplit); + queryFunc(closure, fullName, lm, hash, seqStart, seqEnd, NULL, isSplit); else { /* if chains extend beyond edge of window we need to get * elements that are off the screen * in both directions so we know whether to draw * one or two lines to the edge of the screen. */ #define STARTSLOP 10000 #define MULTIPLIER 10 #define MAXLOOK 100000 extra = (STARTSLOP < maxOverLeft) ? STARTSLOP : maxOverLeft; start = seqStart - extra; extra = (STARTSLOP < maxOverRight) ? STARTSLOP : maxOverRight; end = seqEnd + extra; - doQuery(conn, fullName, lm, hash, start, end, NULL, isSplit); + queryFunc(closure, fullName, lm, hash, start, end, NULL, isSplit); for (lf = tg->items; lf != NULL; lf = lf->next) { if (lf->components != NULL) slSort(&lf->components, linkedFeaturesCmpStart); extra = (STARTSLOP < maxOverRight)?STARTSLOP:maxOverRight; end = seqEnd + extra; for (lastSf=sf=lf->components; sf; lastSf=sf, sf=sf->next) ; while (lf->end > end ) { /* get out if we have an element off right side */ if (( (lastSf != NULL) &&(lastSf->end > seqEnd)) || (extra > MAXLOOK)) break; extra *= MULTIPLIER; start = end; end = start + extra; - doQuery(conn, fullName, lm, hash, start, end, lf->extra, isSplit); + queryFunc(closure, fullName, lm, hash, start, end, lf->extra, isSplit); if (lf->components != NULL) slSort(&lf->components, linkedFeaturesCmpStart); for (sf=lastSf; sf != NULL; lastSf=sf, sf=sf->next) ; } /* if we didn't find an element off to the right , add one */ if ((lf->end > seqEnd) && ((lastSf == NULL) ||(lastSf->end < seqEnd))) { lmAllocVar(lm, sf); sf->start = seqEnd; sf->end = seqEnd+1; sf->grayIx = lf->grayIx; sf->qStart = 0; sf->qEnd = sf->qStart + (sf->end - sf->start); @@ -205,59 +275,120 @@ } /* we know we have a least one component off right * now look for one off left */ extra = (STARTSLOP < maxOverLeft) ? STARTSLOP:maxOverLeft; start = seqStart - extra; while((extra < MAXLOOK) && (lf->start < seqStart) && (lf->components != NULL) && (lf->components->start > seqStart)) { extra *= MULTIPLIER; end = start; start = end - extra; if (start < 0) start = 0; - doQuery(conn, fullName, lm, hash, start, end, lf->extra, isSplit); + queryFunc(closure, fullName, lm, hash, start, end, lf->extra, isSplit); slSort(&lf->components, linkedFeaturesCmpStart); } if ((lf->components != NULL) && (lf->components->start > seqStart) && (lf->start < lf->components->start)) { lmAllocVar(lm, sf); sf->start = 0; sf->end = 1; sf->grayIx = lf->grayIx; sf->qStart = lf->components->qStart; sf->qEnd = sf->qStart + (sf->end - sf->start); sf->next = lf->components; lf->components = sf; slSort(&lf->components, linkedFeaturesCmpStart); } } } } linkedFeaturesDraw(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); /* Cleanup time. */ for (lf = tg->items; lf != NULL; lf = lf->next) lf->components = NULL; lmCleanup(&lm); freeHash(&hash); hFreeConn(&conn); } +void bigChainLoadItems(struct track *tg) +/* Load up all of the chains from correct table into tg->items + * item list. At this stage to conserve memory for other tracks + * we don't load the links into the components list until draw time. */ +{ +struct linkedFeatures *list = NULL, *lf; +int qs; +char *optionChrStr; +struct cartOptions *chainCart; + +chainCart = (struct cartOptions *) tg->extraUiData; + +optionChrStr = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, + "chromFilter", "All"); + +struct bbiFile *bbi = fetchBbiForTrack(tg); +struct lm *lm = lmInit(0); +struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chromName, winStart, winEnd, 0, lm); +int fieldCount = 11; +char *bedRow[fieldCount]; +char startBuf[16], endBuf[16]; + +for (bb = bbList; bb != NULL; bb = bb->next) + { + bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); + struct bed *bed = bedLoadN(bedRow, 6); + lf = bedMungToLinkedFeatures(&bed, tg->tdb, fieldCount, + 0, 1000, FALSE); + + if (*bedRow[5] == '-') + { + lf->orientation = -1; + qs = sqlUnsigned(bedRow[8]) - sqlUnsigned(bedRow[10]); + } + else + { + lf->orientation = 1; + qs = sqlUnsigned(bedRow[9]); + } + + int len = strlen(bedRow[7]) + 32; + lf->name = needMem(len); + safef(lf->name, len, "%s %c %dk", bedRow[7], *bedRow[5], qs/1000); + lf->extra = cloneString(bedRow[3]); + lf->components = NULL; + slAddHead(&list, lf); + } + +/* Make sure this is sorted if in full mode. Sort by score when + * coloring by score and in dense */ +if (tg->visibility != tvDense) + slSort(&list, linkedFeaturesCmpStart); +else if ((tg->visibility == tvDense) && + (chainCart->chainColor == chainColorScoreColors)) + slSort(&list, chainCmpScore); +else + slReverse(&list); +tg->items = list; + +} + void chainLoadItems(struct track *tg) /* Load up all of the chains from correct table into tg->items * item list. At this stage to conserve memory for other tracks * we don't load the links into the components list until draw time. */ { char *table = tg->table; struct chain chain; int rowOffset; char **row; struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr = NULL; struct linkedFeatures *list = NULL, *lf; int qs; char *optionChrStr; char extraWhere[128] ; @@ -409,21 +540,25 @@ } else { char *optionStr; /* this old option was broken before */ optionStr = cartUsualStringClosestToHome(cart, tdb, FALSE, "color", "on"); if (differentWord("on",optionStr)) { setNoColor(tg); chainCart->chainColor = chainColorNoColors; } else chainCart->chainColor = chainColorChromColors; } + +if (tg->isBigBed) + tg->loadItems = bigChainLoadItems; +else tg->loadItems = chainLoadItems; tg->drawItems = chainDraw; tg->mapItemName = lfMapNameFromExtra; tg->subType = lfSubChain; tg->extraUiData = (void *) chainCart; }