5be304c4bdd41bd4452a4b9f1b8fcf37930079e4 braney Fri Feb 3 11:09:59 2017 -0800 allow arbitrary fields with a bigBed file to be used for labels. #18782 diff --git src/hg/hgTracks/bedTrack.c src/hg/hgTracks/bedTrack.c index 5fb6a7e..27c3256 100644 --- src/hg/hgTracks/bedTrack.c +++ src/hg/hgTracks/bedTrack.c @@ -20,30 +20,77 @@ /* Load first six fields of bed. * Add ~seq1~seq2 to end of name * Then remove the sequence to extra field when we convert to linkedFeature. * Assumes seq1 and seq2 are in row[6] and row[7], as they would be with a * pairedTagAlign type (hg/lib/encode/pairedTagAlign.as). It would be good to be * able to check these columns exist but we dont have the sqlResult here. */ { char buf[1024]; struct bed *ret = bedLoad6(row); safef(buf, sizeof(buf), "%s%c%s%c%s", ret->name, SEQ_DELIM, row[6], SEQ_DELIM, row[7]); freez(&(ret->name)); ret->name = cloneString(buf); return ret; } +static void calculateLabelFields(struct track *track) +/* Figure out which fields are available to label a bigBed track. */ +{ +char *labelFields = trackDbSettingClosestToHome(track->tdb, "labelFields"); + +if (labelFields == NULL) + { + // if there is a name, use it by default, otherwise no label by default + if (track->bedSize > 3) + slAddHead(&track->labelColumns, slIntNew(3)); + } +else + { + char cartVar[1024]; + // what has the user said to use as a label + safef(cartVar, sizeof cartVar, "%s.label", track->tdb->track); + struct hashEl *labelEl = cartFindPrefix(cart, cartVar); + struct hash *labelHash = newHash(5); + struct slName *thisLabel, *labelIds = slNameListFromComma(labelFields); + + // fill hash with fields that should be used for labels + if (labelEl == NULL) + hashAdd(labelHash, labelIds->name, "1"); + else + { + for(; labelEl; labelEl = labelEl->next) + hashAdd(labelHash, &labelEl->name[strlen(cartVar) + 1], labelEl->val); + } + + struct asObject *as = asForDb(track->tdb, database); + + for(thisLabel = labelIds; thisLabel; thisLabel = thisLabel->next) + { + char *str = hashFindVal(labelHash,thisLabel->name); + + if ((str != NULL) && sameString(str, "1")) + { + unsigned colNum = asColumnFindIx(as->columnList, thisLabel->name); + + // put this column number in the list of columns to use to make label + slAddHead(&track->labelColumns, slIntNew(colNum)); + } + } + slReverse(&track->labelColumns); + } +} + void loadSimpleBed(struct track *tg) /* Load the items in one track - just move beds in * window... */ { struct bed *(*loader)(char **row); struct bed *bed, *list = NULL; char **row; int rowOffset; char *words[3]; int wordCt; char query[128]; char *setting = NULL; bool doScoreCtFilter = FALSE; int scoreFilterCt = 0; char *topTable = NULL; @@ -91,34 +138,37 @@ struct bedTabixFile *btf = bedTabixFileMayOpen(bigDataUrl, NULL, 0, 0); list = bedTabixReadBeds(btf, chromName, winStart, winEnd, loader); bedTabixFileClose(&btf); } else if (tg->isBigBed) { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks char *scoreFilter = cartOrTdbString(cart, tg->tdb, "scoreFilter", NULL); struct lm *lm = lmInit(0); struct bigBedInterval *bb, *bbList = bigBedSelectRange(tg, chromName, winStart, winEnd, lm); char *bedRow[32]; char startBuf[16], endBuf[16]; int minScore = 0; if (scoreFilter) minScore = atoi(scoreFilter); + tg->itemName = bigBedItemName; + calculateLabelFields(tg); for (bb = bbList; bb != NULL; bb = bb->next) { bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow)); bed = loader(bedRow); + bed->label = makeLabel(tg, bb); if (scoreFilter == NULL || bed->score >= minScore) slAddHead(&list, bed); } lmCleanup(&lm); } else { struct sqlConnection *conn = hAllocConnTrack(database, tg->tdb); struct sqlResult *sr = NULL; /* limit to items above a specified score */ char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL); if (doScoreCtFilter && (topTable != NULL) && hTableExists(database, topTable)) { sqlSafef(query, sizeof(query),"select * from %s order by score desc limit %d", topTable, scoreFilterCt); @@ -441,30 +491,31 @@ { struct sqlResult *sr; char **row; int rowOffset; struct bed *bed; struct linkedFeatures *lfList = NULL, *lf; struct trackDb *tdb = tg->tdb; int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0")); int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000")); boolean useItemRgb = FALSE; useItemRgb = bedItemRgb(tdb); if (tg->isBigBed) { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks + calculateLabelFields(tg); bigBedAddLinkedFeaturesFrom(tg, chromName, winStart, winEnd, scoreMin, scoreMax, useItemRgb, 12, &lfList); } else { /* Use tg->tdb->track because subtracks inherit composite track's tdb * by default, and the variable is named after the composite track. */ struct sqlConnection *conn = hAllocConn(database); char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL); if (scoreFilterClause != NULL) { sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd,scoreFilterClause, &rowOffset); freeMem(scoreFilterClause); } else