dbb7cbfd254794919a8e491cc3d3eb7c6009ba15 angie Tue Jan 25 14:58:05 2011 -0800 Track #1684 (SNPs 132 (dbSNP)): Added new coloring and filtering optionsfor new columns exceptions and bitfields. Fixed remaining hardcoded cart var names to use track name, keeping backwards compat with old sessions. Lots of refactoring -- got rid of snp125Extended business (mostly so I wouldn't have to make a snp132Extended); color is stored in snp->weight now, and extraName stuff overwrites name. Added new color-sorting in squish mode so the most interesting SNPs appear at the top. Also added new trackDb var defaultMaxWeight for the NonUnique subset (so its items aren't invisible by default). diff --git src/hg/hgTracks/variation.c src/hg/hgTracks/variation.c index a0854a1..1754ee6 100644 --- src/hg/hgTracks/variation.c +++ src/hg/hgTracks/variation.c @@ -1,45 +1,53 @@ /* variation.c - hgTracks routines that are specific to the tracks in * the variation group */ #include "variation.h" #include "imageV2.h" static char const rcsid[] = "$Id: variation.c,v 1.148 2010/06/07 16:54:21 angie Exp $"; static double snp125AvHetCutoff = SNP125_DEFAULT_MIN_AVHET; static int snp125WeightCutoff = SNP125_DEFAULT_MAX_WEIGHT; +static int snp132MinSubmitters = 0; // Globals for caching cart coloring and filtering settings for snp125+ tracks: -static char **snp125LocTypeCart = NULL; -static char **snp125ClassCart = NULL; -static char **snp125MolTypeCart = NULL; -static char **snp125ValidCart = NULL; +static enum snp125ColorSource snp125ColorSource = SNP125_DEFAULT_COLOR_SOURCE; +static enum snp125Color *snp125LocTypeCart = NULL; +static enum snp125Color *snp125ClassCart = NULL; +static enum snp125Color *snp125MolTypeCart = NULL; +static enum snp125Color *snp125ValidCart = NULL; static struct hash *snp125FuncCartColorHash = NULL; static struct hash *snp125FuncCartNameHash = NULL; +static enum snp125Color *snp132ExceptionsCart = NULL; +static enum snp125Color *snp132BitfieldsCart = NULL; static boolean snp125LocTypeFilterOn = FALSE; static boolean snp125ClassFilterOn = FALSE; static boolean snp125MolTypeFilterOn = FALSE; static boolean snp125ValidFilterOn = FALSE; static boolean snp125FuncFilterOn = FALSE; +static boolean snp132ExceptionFilterOn = FALSE; +static boolean snp132BitfieldFilterOn = FALSE; static struct slName *snp125LocTypeFilter = NULL; static struct slName *snp125ClassFilter = NULL; static struct slName *snp125MolTypeFilter = NULL; static struct slName *snp125ValidFilter = NULL; static struct slName *snp125FuncFilter = NULL; +static struct slName *snp132ExceptionFilter = NULL; +static struct slName *snp132BitfieldFilter = NULL; void filterSnpMapItems(struct track *tg, boolean (*filter) (struct track *tg, void *item)) /* Filter out items from track->itemList. */ { filterSnpItems(tg, filter); } void filterSnpItems(struct track *tg, boolean (*filter) (struct track *tg, void *item)) /* Filter out items from track->itemList. */ { struct slList *newList = NULL, *el, *next; for (el = tg->items; el != NULL; el = next) @@ -96,30 +104,40 @@ if (el->avHet < snp125AvHetCutoff) return FALSE; return TRUE; } boolean snp125WeightFilterItem(void *item) /* Return TRUE if item passes filter. */ { struct snp125 *el = item; if (el->weight > snp125WeightCutoff) return FALSE; return TRUE; } +boolean snp132MinSubmittersFilterItem(void *item) +/* Return TRUE if item passes filter. */ +{ +struct snp132Ext *el = item; + +if (el->submitterCount < snp132MinSubmitters) + return FALSE; +return TRUE; +} + boolean snpSourceFilterItem(struct track *tg, void *item) /* Return TRUE if item passes filter, i.e. has no excluded property. */ { struct snp *el = item; int snpSource = 0; for (snpSource=0; snpSource<snpSourceCartSize; snpSource++) if (containsStringNoCase(el->source,snpSourceDataName[snpSource])) if (sameString(snpSourceCart[snpSource], "exclude") ) return FALSE; return TRUE; } boolean snpMolTypeFilterItem(struct track *tg, void *item) /* Return TRUE if item passes filter, i.e. has no excluded property. */ @@ -253,354 +271,574 @@ if ( sameString(snpLocTypeCart[snpLocType], "exclude") ) return FALSE; return TRUE; } static boolean snp125LocTypeFilterItem(void *item) /* Return TRUE if item passes filter, i.e. has an included property. */ { struct snp125 *el = (struct snp125 *)item; if (! snp125LocTypeFilterOn) return TRUE; else return slNameInList(snp125LocTypeFilter, el->locType); } +static boolean snp132ExceptionFilterItem(void *item) +/* Return TRUE if item passes filter, i.e. has an included property. */ +{ +struct snp132Ext *el = item; +if (! snp132ExceptionFilterOn) + return TRUE; +else + { + if (isEmpty(el->exceptions) && slNameInList(snp132ExceptionFilter, "NoExceptions")) + return TRUE; + char *s = el->exceptions, *e; + char val[256]; // Longest exception name is much shorter than this + while (s != NULL && s[0] != 0) + { + e = strchr(s, ','); + if (e == NULL) + return slNameInList(snp132ExceptionFilter, s); + else + { + safencpy(val, sizeof(val), s, e-s); + if (slNameInList(snp132ExceptionFilter, val)) + return TRUE; + e += 1; + } + s = e; + } + return FALSE; + } +} + +static boolean snp132BitfieldFilterItem(void *item) +/* Return TRUE if item passes filter, i.e. has an included property. */ +{ +struct snp132Ext *el = item; +if (! snp132BitfieldFilterOn) + return TRUE; +else + { + if (isEmpty(el->bitfields) && slNameInList(snp132BitfieldFilter, "")) + return TRUE; + char *s = el->bitfields, *e; + char val[256]; // Longest bitfield name is much shorter than this + while (s != NULL && s[0] != 0) + { + e = strchr(s, ','); + if (e == NULL) + return slNameInList(snp132BitfieldFilter, s); + else + { + safencpy(val, sizeof(val), s, e-s); + if (slNameInList(snp132BitfieldFilter, val)) + return TRUE; + e += 1; + } + s = e; + } + return FALSE; + } +} + void filterSnp125Items(struct track *tg, int version) /* Filter out items from track->itemList using snp125 filters. */ { struct slList *newList = NULL, *el, *next; for (el = tg->items; el != NULL; el = next) { next = el->next; if (snp125AvHetFilterItem(el) && snp125WeightFilterItem(el) && snp125MolTypeFilterItem(el) && snp125ClassFilterItem(el) && snp125ValidFilterItem(el) && snp125FuncFilterItem(el) && - (version >= 128 || snp125LocTypeFilterItem(el))) + (version >= 128 || snp125LocTypeFilterItem(el)) && + (version < 132 || + (snp132MinSubmittersFilterItem(el) && + snp132ExceptionFilterItem(el) && + snp132BitfieldFilterItem(el)))) slAddHead(&newList, el); } slReverse(&newList); tg->items = newList; } struct orthoBed *orthoBedLoad(char **row) /* Load a bed from row fetched with select * from bed * from database. Dispose of this with bedFree(). */ /* This should be moved to kent/src/hg/lib. */ { struct orthoBed *ret; if (sameString(row[10], "?")) return NULL; AllocVar(ret); ret->chrom = cloneString(row[0]); ret->chromStart = sqlUnsigned(row[1]); ret->chromEnd = sqlUnsigned(row[2]); ret->name = cloneString(row[3]); ret->chimp = cloneString(row[10]); return ret; } int snpOrthoCmp(const void *va, const void *vb) -/* Compare for sort based on bed4 */ +/* Compare for sort based on bed4 -- like bedCmp, but more + * deterministic because it uses chromEnd and name too. */ { -struct snp125Extended *a = *((struct snp125Extended **)va); -struct orthoBed *b = *((struct orthoBed **)vb); +struct bed4 *a = *((struct bed4 **)va); +struct bed4 *b = *((struct bed4 **)vb); int dif; if(a==0||b==0) return 0; dif = differentWord(a->chrom, b->chrom); if (dif == 0) dif = a->chromStart - b->chromStart; if (dif == 0) dif = a->chromEnd - b->chromEnd; if (dif == 0) dif = differentWord(a->name, b->name); return dif; } void setSnp125ExtendedNameExtra(struct track *tg) /* add extra text to be drawn in snp name field. This works by - walking through two sorted lists and updating the nameExtra value + walking through two sorted lists and updating the name value for the SNP list with data from a table of orthologous state information */ { +char cartVar[512]; + safef(cartVar, sizeof(cartVar), "%s.extendedNames", tg->tdb->track); +boolean enabled = cartUsualBoolean(cart, cartVar, + // Check old cart var name for backwards compatibility w/ old sessions: + cartUsualBoolean(cart, "snp125ExtendedNames", FALSE)); +if (!enabled) + return; struct sqlConnection *conn = hAllocConn(database); int rowOffset = 0; char **row = NULL; -struct slList *snpItemList = tg->items; /* list of SNPs */ -struct slList *snpItem = snpItemList; -struct slList *orthoItemList = NULL; /* list of orthologous state info */ -struct slList *orthoItem = orthoItemList; +struct orthoBed *orthoItemList = NULL; /* list of orthologous state info */ +struct orthoBed *orthoItem = orthoItemList; char *orthoTable = snp125OrthoTable(tg->tdb, NULL); struct sqlResult *sr = NULL; int cmp = 0; struct dyString *extra = newDyString(256); /* if orthologous info is not available, don't add it! */ if(isEmpty(orthoTable) || !sqlTableExists(conn, orthoTable)) { hFreeConn(&conn); return; } /* get list of orthologous alleles */ sr = hRangeQuery(conn, orthoTable, chromName, winStart, winEnd, NULL, &rowOffset); while ((row = sqlNextRow(sr)) != NULL) { - orthoItem = (struct slList *)orthoBedLoad(row + rowOffset); + orthoItem = orthoBedLoad(row + rowOffset); if (orthoItem) slAddHead(&orthoItemList, orthoItem); } /* List of SNPs is already sorted, so sort list of Ortho info */ -slSort(&orthoItemList, bedCmp); +slSort(&orthoItemList, snpOrthoCmp); /* Walk through two sorted lists together */ -snpItem = snpItemList; +struct snp125 *snpItem = tg->items; orthoItem = orthoItemList; while (snpItem!=NULL && orthoItem!=NULL) { /* check to see that we're not at the end of either list and that * the two list elements represent the same human position */ cmp = snpOrthoCmp(&snpItem, &orthoItem); if (cmp < 0) { snpItem = snpItem->next; continue; } if (cmp > 0) { orthoItem = orthoItem->next; continue; } - /* update the snp->extraName with the ortho data */ - dyStringPrintf(extra, " %s>%s", ((struct orthoBed *)orthoItem)->chimp, ((struct snp125Extended *)snpItem)->observed); - ((struct snp125Extended *)snpItem)->nameExtra = cloneString(extra->string); + /* update the snp->name with the ortho data */ + dyStringPrintf(extra, "%s %s>%s", snpItem->name, orthoItem->chimp, snpItem->observed); + snpItem->name = cloneString(extra->string); dyStringClear(extra); /* increment the list pointers */ snpItem = snpItem->next; orthoItem = orthoItem->next; } -tg->items=snpItemList; freeDyString(&extra); sqlFreeResult(&sr); hFreeConn(&conn); } -Color snp125ExtendedColor(struct track *tg, void *item, struct hvGfx *hvg) -/* Return color of snp track item. */ +Color snp125Color(struct track *tg, void *item, struct hvGfx *hvg) +/* Return color of snp track item -- which we stash in the weight column (only the bed4 + * fields of snp are used at draw time). */ { -return ((struct snp125Extended *)item)->color; +struct snp125 *snp = item; +return (Color)(snp->weight); } -int snp125ExtendedColorCmpRaw(const Color ca, const char *aName, - const Color cb, const char *bName) +int snp125ColorCmpRaw(const Color ca, const char *aName, const Color cb, const char *bName) /* Compare to sort based on color -- black first, red last. This is not * a slSort Cmp function, just a comparator of the values. */ { /* order is important here */ if (ca==cb) return 0; if (ca==MG_RED) return 1; if (cb==MG_RED) return -1; if (ca==MG_GREEN) return 1; if (cb==MG_GREEN) return -1; if (ca==MG_BLUE) return 1; if (cb==MG_BLUE) return -1; if (ca==MG_GRAY) return 1; if (cb==MG_GRAY) return -1; if (ca==MG_BLACK) return 1; if (cb==MG_BLACK) return -1; hPrintComment("SNP track: colors %d (%s) and %d (%s) not known", ca, aName, cb, bName); return 0; } -int snp125ExtendedColorCmp(const void *va, const void *vb) +int snp125ColorCmp(const void *va, const void *vb) /* Compare to sort based on color -- black first, red last */ { -const struct snp125Extended *a = *((struct snp125Extended **)va); -const struct snp125Extended *b = *((struct snp125Extended **)vb); -const Color ca = a->color; -const Color cb = b->color; +const struct snp125 *a = *((struct snp125 **)va); +const struct snp125 *b = *((struct snp125 **)vb); +const Color ca = (Color)(a->weight); +const Color cb = (Color)(b->weight); -return snp125ExtendedColorCmpRaw(ca, a->name, cb, b->name); +return snp125ColorCmpRaw(ca, a->name, cb, b->name); } -void sortSnp125ExtendedByColor(struct track *tg) -/* Sort snps so that more functional snps (non-synonymous, splice site) are printed last. - * Color calculation is used as an intermediate step to represent severity. */ +int snp125ColorCmpDesc(const void *va, const void *vb) +/* Compare to sort based on color -- red first, black last */ { -/* snp and snpMap have different loaders that do not support the color - * attribute of the snp125Extended struct */ -if(differentString(tg->table,"snp") && differentString(tg->table,"snpMap")) - slSort(&tg->items, snp125ExtendedColorCmp); +const struct snp125 *a = *((struct snp125 **)va); +const struct snp125 *b = *((struct snp125 **)vb); +const Color ca = (Color)(a->weight); +const Color cb = (Color)(b->weight); + +return snp125ColorCmpRaw(cb, b->name, ca, a->name); } -void loadSnp125Extended(struct track *tg) -/* load snps from snp125 table, ortho alleles from snpXXXortho table, - * and return in extended struct */ +static enum snp125Color *snp125ColorsFromCart(char *track, char *attribute, + char *vars[], boolean varsAreOld, char *defaults[], int varCount) +/* Look up attribute colors in cart using both old and new cart var names where applicable. */ { -struct sqlConnection *conn = hAllocConn(database); -int rowOffset = 0; -char **row = NULL; -struct slList *itemList = tg->items; -struct slList *item = itemList; -struct sqlResult *sr = NULL; -struct snp125Extended *se = NULL; -enum trackVisibility visLim = limitVisibility(tg); -int version = snpVersion(tg->table); -int i = 0; +enum snp125Color *cartColors = NULL; +AllocArray(cartColors, varCount); +int i; +for (i=0; i < varCount; i++) + { + char cartVar[512]; + safef(cartVar, sizeof(cartVar), "%s.%s%s", track, attribute, + (varsAreOld ? snp125OldColorVarToNew(vars[i], attribute) : vars[i])); + char *defaultCol = defaults[i]; + if (varsAreOld) + defaultCol = cartUsualString(cart, vars[i], defaultCol); + char *col = cartUsualString(cart, cartVar, defaultCol); + cartColors[i] = stringArrayIx(col, snp125ColorLabel, snp125ColorArraySize); + } +return cartColors; +} -snp125AvHetCutoff = cartUsualDouble(cart, "snp125AvHetCutoff", SNP125_DEFAULT_MIN_AVHET); -snp125WeightCutoff = cartUsualInt(cart, "snp125WeightCutoff", SNP125_DEFAULT_MAX_WEIGHT); -snp125ExtendedNames = cartUsualBoolean(cart, "snp125ExtendedNames", FALSE); +static void snp125SetupFiltersAndColorsFromCart(struct trackDb *tdb) +/* Load the controls set by hgTrackUi into global vars. */ +{ +char *track = tdb->track; +char cartVar[512]; +safef(cartVar, sizeof(cartVar), "%s.minAvHet", track); +snp125AvHetCutoff = cartUsualDouble(cart, cartVar, + // Check old cart var name: + cartUsualDouble(cart, "snp125AvHetCutoff", SNP125_DEFAULT_MIN_AVHET)); +safef(cartVar, sizeof(cartVar), "%s.maxWeight", track); +int defaultMaxWeight = SNP125_DEFAULT_MAX_WEIGHT; +char *setting = trackDbSetting(tdb, "defaultMaxWeight"); +if (isNotEmpty(setting)) + defaultMaxWeight = atoi(setting); +snp125WeightCutoff = cartUsualInt(cart, cartVar, + // Check old cart var name and tdb default: + cartUsualInt(cart, "snp125WeightCutoff", defaultMaxWeight)); +safef(cartVar, sizeof(cartVar), "%s.minSubmitters", track); +snp132MinSubmitters = cartUsualInt(cart, cartVar, SNP132_DEFAULT_MIN_SUBMITTERS); -char *track = tg->tdb->track; snp125MolTypeFilter = snp125FilterFromCart(cart, track, "molType", &snp125MolTypeFilterOn); snp125ClassFilter = snp125FilterFromCart(cart, track, "class", &snp125ClassFilterOn); snp125ValidFilter = snp125FilterFromCart(cart, track, "valid", &snp125ValidFilterOn); snp125FuncFilter = snp125FilterFromCart(cart, track, "func", &snp125FuncFilterOn); snp125LocTypeFilter = snp125FilterFromCart(cart, track, "locType", &snp125LocTypeFilterOn); - -AllocArray(snp125MolTypeCart, snp125MolTypeArraySize); -for (i=0; i < snp125MolTypeArraySize; i++) - snp125MolTypeCart[i] = cartUsualString(cart, snp125MolTypeStrings[i], snp125MolTypeDefault[i]); -AllocArray(snp125ClassCart, snp125ClassArraySize); -for (i=0; i < snp125ClassArraySize; i++) - snp125ClassCart[i] = cartUsualString(cart, snp125ClassStrings[i], snp125ClassDefault[i]); -AllocArray(snp125ValidCart, snp125ValidArraySize); -for (i=0; i < snp125ValidArraySize; i++) - snp125ValidCart[i] = cartUsualString(cart, snp125ValidStrings[i], snp125ValidDefault[i]); -AllocArray(snp125LocTypeCart, snp125LocTypeArraySize); -for (i=0; i < snp125LocTypeArraySize; i++) - snp125LocTypeCart[i] = cartUsualString(cart, snp125LocTypeStrings[i], snp125LocTypeDefault[i]); +snp132ExceptionFilter = snp125FilterFromCart(cart, track, "exceptions", &snp132ExceptionFilterOn); +snp132BitfieldFilter = snp125FilterFromCart(cart, track, "bitfields", &snp132BitfieldFilterOn); + +safef(cartVar, sizeof(cartVar), "%s.colorSource", track); +char *snp125ColorSourceDefault = snp125ColorSourceLabels[SNP125_DEFAULT_COLOR_SOURCE]; +char *colorSourceCart = cartUsualString(cart, cartVar, + cartUsualString(cart, snp125ColorSourceOldVar, + snp125ColorSourceDefault)); +snp125ColorSource = stringArrayIx(colorSourceCart, snp125ColorSourceLabels, + snp125ColorSourceArraySize); +snp125MolTypeCart = snp125ColorsFromCart(track, "molType", snp125MolTypeOldColorVars, TRUE, + snp125MolTypeDefault, snp125MolTypeArraySize); +snp125ClassCart = snp125ColorsFromCart(track, "class", snp125ClassOldColorVars, TRUE, + snp125ClassDefault, snp125ClassArraySize); +snp125ValidCart = snp125ColorsFromCart(track, "valid", snp125ValidOldColorVars, TRUE, + snp125ValidDefault, snp125ValidArraySize); +snp125LocTypeCart = snp125ColorsFromCart(track, "locType", snp125LocTypeOldColorVars, TRUE, + snp125LocTypeDefault, snp125LocTypeArraySize); +snp132ExceptionsCart = snp125ColorsFromCart(track, "exception", snp132ExceptionVarName, FALSE, + snp132ExceptionDefault, snp132ExceptionArraySize); +snp132BitfieldsCart = snp125ColorsFromCart(track, "bitfield", snp132BitfieldVarName, FALSE, + snp132BitfieldDefault, snp132BitfieldArraySize); snp125FuncCartColorHash = hashNew(0); snp125FuncCartNameHash = hashNew(0); +int i; for (i=0; i < snp125FuncArraySize; i++) { - char *cartVal = cartUsualString(cart, snp125FuncStrings[i], snp125FuncDefault[i]); + safef(cartVar, sizeof(cartVar), "%s.func%s", + track, snp125OldColorVarToNew(snp125FuncOldColorVars[i], "func")); + char *cartVal = cartUsualString(cart, cartVar, + cartUsualString(cart, snp125FuncOldColorVars[i], + snp125FuncDefault[i])); /* There are many function types, some of which are mapped onto * simpler types in snp125Ui.c. First store the indexes of * selected colors of simpler types that we present as coloring * choices; then (below) map the more detailed function types' * indexes onto the simpler types' indexes. */ hashAddInt(snp125FuncCartColorHash, snp125FuncDataName[i], stringArrayIx(cartVal, snp125ColorLabel, snp125ColorArraySize)); /* Similarly, map names. Self-mapping here, synonyms below. */ hashAdd(snp125FuncCartNameHash, snp125FuncDataName[i], snp125FuncDataName[i]); } int j, k; for (j = 0; snp125FuncDataSynonyms[j] != NULL; j++) { + char *canonical = snp125FuncDataSynonyms[j][0]; for (k = 1; snp125FuncDataSynonyms[j][k] != NULL; k++) { hashAddInt(snp125FuncCartColorHash, snp125FuncDataSynonyms[j][k], - hashIntVal(snp125FuncCartColorHash, - snp125FuncDataSynonyms[j][0])); - hashAdd(snp125FuncCartNameHash, snp125FuncDataSynonyms[j][k], - snp125FuncDataSynonyms[j][0]); + hashIntVal(snp125FuncCartColorHash, canonical)); + hashAdd(snp125FuncCartNameHash, snp125FuncDataSynonyms[j][k], canonical); + } } } -/* load SNPs */ -sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); +Color snp125ColorToMg(enum snpColorEnum thisSnpColor) +/* Translate full range of snpColorEnum into memgfx MG_<COLOR>. */ +{ +switch (thisSnpColor) + { + case snp125ColorRed: + return MG_RED; + break; + case snp125ColorGreen: + return MG_GREEN; + break; + case snp125ColorBlue: + return MG_BLUE; + break; + case snp125ColorGray: + return MG_GRAY; + break; + case snp125ColorBlack: + default: + return MG_BLACK; + break; + } +} -if(differentString(tg->table,"snp") && differentString(tg->table,"snpMap")) - while ((row = sqlNextRow(sr)) != NULL) +static void snp125ColorItems(struct track *tg, int version) +/* Use cart settings and snp properties to assign a color to snp -- and stash it in snp->weight. */ { - /* use loader for snp125 table format */ - item = (struct slList *)snp125ExtendedLoad(row + rowOffset); - se = (struct snp125Extended *)item; - se->color = snp125Color(tg, se, NULL); - slAddHead(&itemList, item); +struct snp132Ext *snp; +for (snp = tg->items; snp != NULL; snp = snp->next) + { + enum snp125Color color = snp125ColorBlack; + int valIx; + char *words[128]; + int wordCount, i; + char buf[4096]; + switch (snp125ColorSource) + { + case snp125ColorSourceMolType: + valIx = stringArrayIx(snp->molType, snp125MolTypeDataName, snp125MolTypeArraySize); + if (valIx < 0) + valIx = 0; + color = snp125MolTypeCart[valIx]; + break; + case snp125ColorSourceClass: + valIx = stringArrayIx(snp->class, snp125ClassDataName, snp125ClassArraySize); + if (valIx < 0) + valIx = 0; + color = snp125ClassCart[valIx]; + break; + case snp125ColorSourceValid: + for (i=0; i < snp125ValidArraySize; i++) + if (containsStringNoCase(snp->valid, snp125ValidDataName[i])) + color = snp125ValidCart[i]; + break; + case snp125ColorSourceFunc: + { + safecpy(buf, sizeof(buf), snp->func); + wordCount = chopCommas(buf, words); + for (i = 0; i < wordCount; i++) + { + enum snp125Color wordColor = hashIntVal(snp125FuncCartColorHash, words[i]); + if (snp125ColorCmpRaw(snp125ColorToMg(wordColor), "wordColor", + snp125ColorToMg(color), "color") > 0) + color = wordColor; + } } + break; + case snp125ColorSourceLocType: + valIx = stringArrayIx(snp->locType,snp125LocTypeDataName,snp125LocTypeArraySize); + if (valIx < 0) + valIx = 0; + color = snp125LocTypeCart[valIx]; + break; + case snp125ColorSourceExceptions: + { + if (isEmpty(snp->exceptions)) + color = snp132ExceptionsCart[0]; else + { + safecpy(buf, sizeof(buf), snp->exceptions); + wordCount = chopCommas(buf, words); + for (i = 0; i < wordCount; i++) + { + valIx = stringArrayIx(words[i], snp132ExceptionVarName, snp132ExceptionArraySize); + enum snp125Color wordColor = snp132ExceptionsCart[valIx]; + if (snp125ColorCmpRaw(snp125ColorToMg(wordColor), "wordColor", + snp125ColorToMg(color), "color") > 0) + color = wordColor; + } + } + } + break; + case snp125ColorSourceBitfields: + { + if (isEmpty(snp->bitfields)) + color = snp132BitfieldsCart[0]; + else + { + safecpy(buf, sizeof(buf), snp->bitfields); + wordCount = chopCommas(buf, words); + for (i = 0; i < wordCount; i++) + { + valIx = stringArrayIx(words[i], snp132BitfieldDataName, snp132BitfieldArraySize); + enum snp125Color wordColor = snp132BitfieldsCart[valIx]; + if (snp125ColorCmpRaw(snp125ColorToMg(wordColor), "wordColor", + snp125ColorToMg(color), "color") > 0) + color = wordColor; + } + } + } + break; + default: + color = snp125ColorBlack; + break; + } + snp->weight = snp125ColorToMg(color); + } +} + +static void loadSnp125Basic(struct track *tg, int version, void *(loadFunction)(char **)) +/* load snp125 or snp132Ext items from table */ +{ +struct sqlConnection *conn = hAllocConn(database); +struct snp132Ext *itemList = NULL; +int rowOffset = 0; +char **row = NULL; +struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd, NULL, &rowOffset); while ((row = sqlNextRow(sr)) != NULL) { - /* use loader for pre-snp125 table format */ - item = (struct slList *)snpExtendedLoad(row + rowOffset); - se = (struct snp125Extended *)item; - se->color = snp125Color(tg, se, NULL); - slAddHead(&itemList, item); + struct slList *snp = loadFunction(row + rowOffset); + slAddHead(&itemList, snp); } sqlFreeResult(&sr); hFreeConn(&conn); - tg->items = itemList; +} + +void loadSnp125(struct track *tg) +/* load snps from table, ortho alleles from snpXXXOrthoXXX table, filter and color. */ +{ +int version = snpVersion(tg->table); +if (version >= 132) + loadSnp125Basic(tg, version, (void *)(snp132ExtLoad)); +else if (version >= 125) + loadSnp125Basic(tg, version, (void *)(snp125Load)); +else + errAbort("How was loadSnp125 called on version < 125? (%d)", version); +snp125SetupFiltersAndColorsFromCart(tg->tdb); filterSnp125Items(tg, version); +snp125ColorItems(tg, version); -if (visLim==tvDense) - sortSnp125ExtendedByColor(tg); +if (tg->visibility == tvDense) + slSort(&tg->items, snp125ColorCmp); +else if (tg->visibility == tvSquish) + slSort(&tg->items, snp125ColorCmpDesc); else { - slSort(&tg->items, bedCmp); - if(snp125ExtendedNames && visLim != tvSquish) + slSort(&tg->items, snpOrthoCmp); setSnp125ExtendedNameExtra(tg); - tg->limitedVisSet = FALSE; - limitVisibility(tg); + enum trackVisibility newVis = limitVisibility(tg); + if (newVis == tvDense) + slSort(&tg->items, snp125ColorCmp); + else if (newVis == tvSquish) + slSort(&tg->items, snp125ColorCmpDesc); } } void loadSnpMap(struct track *tg) /* Load up snpMap from database table to track items. */ { int snpMapSource, snpMapType; for (snpMapSource=0; snpMapSource<snpMapSourceCartSize; snpMapSource++) snpMapSourceCart[snpMapSource] = cartUsualString(cart, snpMapSourceStrings[snpMapSource], snpMapSourceDefault[snpMapSource]); for (snpMapType=0; snpMapType<snpMapTypeCartSize; snpMapType++) snpMapTypeCart[snpMapType] = cartUsualString(cart, snpMapTypeStrings[snpMapType], snpMapTypeDefault[snpMapType]); bedLoadItem(tg, "snpMap", (ItemLoader)snpMapLoad); if (!startsWith("hg",database)) return; filterSnpMapItems(tg, snpMapSourceFilterItem); filterSnpMapItems(tg, snpMapTypeFilterItem); } -char *snp125ExtendedName(struct track *tg, void *item) -{ -struct dyString *ds = newDyString(256); -struct snp125Extended *se = item; -char *ret = NULL; - -dyStringPrintf(ds, "%s", se->name); -if (se!=NULL && se->nameExtra != NULL) - dyStringAppend(ds, se->nameExtra); -ret = cloneString(ds->string); -freeDyString(&ds); -return ret; -} - void loadSnp(struct track *tg) /* Load up snp from database table to track items. */ { int i = 0; snpAvHetCutoff = atof(cartUsualString(cart, "snpAvHetCutoff", "0.0")); for (i=0; i < snpSourceCartSize; i++) snpSourceCart[i] = cartUsualString(cart, snpSourceStrings[i], snpSourceDefault[i]); for (i=0; i < snpMolTypeCartSize; i++) snpMolTypeCart[i] = cartUsualString(cart, snpMolTypeStrings[i], snpMolTypeDefault[i]); for (i=0; i < snpClassCartSize; i++) snpClassCart[i] = cartUsualString(cart, snpClassStrings[i], snpClassDefault[i]); for (i=0; i < snpValidCartSize; i++) snpValidCart[i] = cartUsualString(cart, snpValidStrings[i], snpValidDefault[i]); @@ -651,121 +889,30 @@ case snpColorRed: return MG_RED; break; case snpColorGreen: return MG_GREEN; break; case snpColorBlue: return MG_BLUE; break; default: return MG_BLACK; break; } } -Color snp125ColorToMg(enum snpColorEnum thisSnpColor) -/* Translate full range of snpColorEnum into memgfx MG_<COLOR>. */ -{ -switch (thisSnpColor) - { - case snp125ColorRed: - return MG_RED; - break; - case snp125ColorGreen: - return MG_GREEN; - break; - case snp125ColorBlue: - return MG_BLUE; - break; - case snp125ColorGray: - return MG_GRAY; - break; - case snp125ColorBlack: - default: - return MG_BLACK; - break; - } -} - -Color snp125Color(struct track *tg, void *item, struct hvGfx *hvg) -/* Return color of snp track item. */ -{ -struct snp125 *el = item; -enum snp125ColorEnum thisSnpColor = snp125ColorBlack; -char *snpColorSource = cartUsualString(cart, snp125ColorSourceVarName, snp125ColorSourceDefault); -int snpValid = 0; -int index1 = 0; -int index2 = 0; - -index1 = stringArrayIx(snpColorSource, - snp125ColorSourceLabels, snp125ColorSourceArraySize); -switch (index1) - { - case snp125ColorSourceMolType: -//*** seems like we should precompute a mapping directly from el->molType to color -//*** (the second stringArrayIx into snp125MolTypeCart shouldn't be necessary) - index2 = stringArrayIx(el->molType,snp125MolTypeDataName,snp125MolTypeArraySize); - if (index2 < 0) - index2 = 0; - thisSnpColor=(enum snp125ColorEnum)stringArrayIx(snp125MolTypeCart[index2],snp125ColorLabel,snp125ColorArraySize); - break; - case snp125ColorSourceClass: - index2 = stringArrayIx(el->class,snp125ClassDataName,snp125ClassArraySize); - if (index2 < 0) - index2 = 0; - thisSnpColor=(enum snp125ColorEnum)stringArrayIx(snp125ClassCart[index2],snp125ColorLabel,snp125ColorArraySize); - break; - /* valid is a set */ - case snp125ColorSourceValid: - for (snpValid=0; snpValid<snp125ValidArraySize; snpValid++) - if (containsStringNoCase(el->valid, snp125ValidDataName[snpValid])) - thisSnpColor = (enum snp125ColorEnum) stringArrayIx(snp125ValidCart[snpValid],snp125ColorLabel,snp125ColorArraySize); - break; - /* func is a set */ - case snp125ColorSourceFunc: - { - char *words[128]; - int wordCount, i; - char funcString[4096]; - safecpy(funcString, sizeof(funcString), el->func); - wordCount = chopCommas(funcString, words); - for (i = 0; i < wordCount; i++) - { - enum snp125ColorEnum wordColor = (enum snp125ColorEnum) - hashIntVal(snp125FuncCartColorHash, words[i]); - /* This sorting function is a reverse-sort, so use it backwards: */ - if (snp125ExtendedColorCmpRaw( - snp125ColorToMg(wordColor), "wordColor", - snp125ColorToMg(thisSnpColor), "thisSnpColor") > 0) - thisSnpColor = wordColor; - } - } - break; - case snp125ColorSourceLocType: - index2 = stringArrayIx(el->locType,snp125LocTypeDataName,snp125LocTypeArraySize); - if (index2 < 0) - index2 = 0; - thisSnpColor=(enum snp125ColorEnum)stringArrayIx(snp125LocTypeCart[index2],snp125ColorLabel,snp125ColorArraySize); - break; - default: - thisSnpColor = snp125ColorBlack; - break; - } -return snp125ColorToMg(thisSnpColor); -} - Color snpColor(struct track *tg, void *item, struct hvGfx *hvg) /* Return color of snp track item. */ { struct snp *el = item; enum snpColorEnum thisSnpColor = snpColorBlack; char *snpColorSource = cartUsualString(cart, snpColorSourceDataName[0], snpColorSourceDefault[0]); char *validString = NULL; char *funcString = NULL; int snpValid = 0; int snpFunc = 0; int index1 = 0; int index2 = 0; index1 = stringArrayIx(snpColorSource, snpColorSourceStrings, snpColorSourceStringsSize); @@ -857,35 +1004,34 @@ /* Clip here so that text will tend to be more visible... */ if (tg->drawName && vis != tvSquish) mapBoxHc(hvg, s->chromStart, s->chromEnd, x1, y, w, heightPer, tg->track, tg->mapItemName(tg, s), NULL); } void snp125DrawItemAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) /* Draw a single snp125 item at position. */ { struct snp125 *s = item; int heightPer = tg->heightPer; int x1 = round((double)((int)s->chromStart-winStart)*scale) + xOff; int x2 = round((double)((int)s->chromEnd-winStart)*scale) + xOff; int w = x2-x1; -Color itemColor = tg->itemColor(tg, s, hvg); if ( w<1 ) w = 1; -hvGfxBox(hvg, x1, y, w, heightPer, itemColor); +hvGfxBox(hvg, x1, y, w, heightPer, (Color)(s->weight)); /* Clip here so that text will tend to be more visible... */ if (tg->drawName && vis != tvSquish) mapBoxHc(hvg, s->chromStart, s->chromEnd, x1, y, w, heightPer, tg->track, tg->mapItemName(tg, s), NULL); } static void snpMapDrawItems(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw snpMap items. */ { double scale = scaleForPixels(width); int lineHeight = tg->lineHeight; int heightPer = tg->heightPer; int w, y; @@ -1053,39 +1199,36 @@ } void snpMethods(struct track *tg) /* Make track for snps. */ { tg->drawItems = snpDrawItems; tg->drawItemAt = snpDrawItemAt; tg->loadItems = loadSnp; tg->freeItems = freeSnp; tg->itemColor = snpColor; tg->itemNameColor = snpColor; } void snp125Methods(struct track *tg) { -char *orthoTable = snp125OrthoTable(tg->tdb, NULL); tg->drawItems = snpDrawItems; tg->drawItemAt = snp125DrawItemAt; tg->freeItems = freeSnp125; -tg->loadItems = loadSnp125Extended; -tg->itemNameColor = snp125ExtendedColor; -tg->itemColor = snp125ExtendedColor; -if (isNotEmpty(orthoTable) && hTableExists(database, orthoTable)) - tg->itemName = snp125ExtendedName; +tg->loadItems = loadSnp125; +tg->itemNameColor = snp125Color; +tg->itemColor = snp125Color; } char *perlegenName(struct track *tg, void *item) /* return the actual perlegen name, in form xx/yyyy: cut off xx/ and return yyyy */ { char *name; struct linkedFeatures *lf = item; name = strstr(lf->name, "/"); if (name != NULL) name ++; if (name != NULL) return name; return "unknown"; }