45c5e17075e31abf2735b09ca201d29ce6e0e1f4 kate Thu Jun 29 18:17:22 2017 -0700 Add trackUi (body map and right-click versions) and implement filters in hgTracks. refs #15646 diff --git src/hg/hgTracks/gtexEqtlClusterTrack.c src/hg/hgTracks/gtexEqtlClusterTrack.c index 26c178a..cadd2c8 100644 --- src/hg/hgTracks/gtexEqtlClusterTrack.c +++ src/hg/hgTracks/gtexEqtlClusterTrack.c @@ -1,122 +1,223 @@ /* gtexEqtlClusterTrack - Track of clustered expression QTL's from GTEx */ /* Copyright (C) 2017 The Regents of the University of California * See README in this or parent directory for licensing information. */ #include "common.h" #include "dystring.h" #include "hgTracks.h" #include "gtexInfo.h" #include "gtexTissue.h" +#include "gtexUi.h" #include "gtexEqtlCluster.h" struct gtexEqtlClusterTrack -/* Track info */ +/* Track info for filtering (maybe later for draw, map) */ { - int tissueCount; /* Tissue count */ - struct hash *tissueHash; /* Tissue info, keyed by UCSC name */ + struct gtexTissue *tissues; /* Tissue names, descriptions */ + struct hash *tissueHash; /* Tissue info, keyed by UCSC name, filtered by UI */ + double minEffect; /* Effect size filter (abs value) */ + double minProb; /* Probability filter */ }; static struct gtexEqtlCluster *loadOne(char **row) /* Load up gtexEqtlCluster from array of strings. */ { return gtexEqtlClusterLoad(row); } +static boolean filterTissues(struct track *track, struct gtexEqtlClusterTrack *extras) +/* Check cart for tissue selection */ +{ +char *version = gtexVersionSuffix(track->table); +extras->tissues = gtexGetTissues(version); +extras->tissueHash = hashNew(0); +if (cartListVarExistsAnyLevel(cart, track->tdb, FALSE, GTEX_TISSUE_SELECT)) + { + struct slName *selectedValues = cartOptionalSlNameListClosestToHome(cart, track->tdb, + FALSE, GTEX_TISSUE_SELECT); + if (selectedValues != NULL) + { + struct slName *name; + for (name = selectedValues; name != NULL; name = name->next) + hashAdd(extras->tissueHash, name->name, name->name); + return TRUE; + } + } +/* no filter */ +struct gtexTissue *tis = NULL; +for (tis = extras->tissues; tis != NULL; tis = tis->next) + hashAdd(extras->tissueHash, tis->name, tis->name); +return FALSE; +} + +static void excludeTissue(struct gtexEqtlCluster *eqtl, int i) +/* Mark the tissue to exclude from display */ +{ +eqtl->expScores[i] = 0.0; +} + +static boolean isExcludedTissue(struct gtexEqtlCluster *eqtl, int i) +/* Check if eQTL is excluded */ +{ +return (eqtl->expScores[i] == 0.0); +} + +static boolean eqtlIncludeFilter(struct track *track, void *item) +/* Apply all filters (except gene) to eQTL item */ +{ +int i; +int excluded = 0; +double maxEffect = 0.0; +double maxProb = 0.0; +struct gtexEqtlCluster *eqtl = (struct gtexEqtlCluster *)item; +struct gtexEqtlClusterTrack *extras = (struct gtexEqtlClusterTrack *)track->extraUiData; +for (i=0; iexpCount; i++) + { + if (hashFindVal(extras->tissueHash, eqtl->expNames[i])) + { + maxEffect = fmax(maxEffect, fabs(eqtl->expScores[i])); + maxProb = fmax(maxProb, fabs(eqtl->expProbs[i])); + } + else + { + excludeTissue(eqtl, i); + excluded++; + } + } +// exclude if no tissues match selector +//uglyf(", excluded: %d, maxEffect: %0.2f (min %0.2f), maxProb: %0.2f (min %0.2f)", + //excluded, maxEffect, extras->minEffect, maxProb, extras->minProb); +if (excluded == eqtl->expCount || + // or if variant has no selected tissue where effect size is above cutoff + maxEffect < extras->minEffect || + // or if variant has no selected tissue where probability is above cutoff + maxProb < extras->minProb) + return FALSE; +return TRUE; +} + static void gtexEqtlClusterLoadItems(struct track *track) -/* Load all items (and motifs if table is present) in window */ +/* Load items in window and prune those that don't pass filter */ { +/* initialize track info */ struct gtexEqtlClusterTrack *extras; AllocVar(extras); track->extraUiData = extras; -char *version = gtexVersionSuffix(track->table); -struct gtexTissue *tissues = gtexGetTissues(version); -struct hash *tisHash = hashNew(0); -extras->tissueHash = tisHash; -struct gtexTissue *tis = NULL; -for (tis = tissues; tis != NULL; tis = tis->next) - hashAdd(extras->tissueHash, tis->name, tis); -bedLoadItem(track, track->table, (ItemLoader)loadOne); + +// filter by gene via SQL +char cartVar[64]; +safef(cartVar, sizeof cartVar, "%s.%s", track->track, GTEX_EQTL_GENE); +char *gene = cartNonemptyString(cart, cartVar); +char *where = NULL; +if (gene) + { + struct dyString *ds = dyStringNew(0); + sqlDyStringPrintfFrag(ds, "%s = '%s'", GTEX_EQTL_GENE_FIELD, gene); + where = dyStringCannibalize(&ds); + } +bedLoadItemWhere(track, track->table, where, (ItemLoader)loadOne); +//uglyf("DEBUG: loaded items: %d\n", slCount(track->items)); + +safef(cartVar, sizeof cartVar, "%s.%s", track->track, GTEX_EQTL_EFFECT); +extras->minEffect = fabs(cartUsualDouble(cart, cartVar, GTEX_EFFECT_MIN_DEFAULT)); +safef(cartVar, sizeof cartVar, "%s.%s", track->track, GTEX_EQTL_PROBABILITY); +extras->minProb = cartUsualDouble(cart, cartVar, 0.0); +boolean hasTissueFilter = filterTissues(track, extras); +if (!hasTissueFilter && extras->minEffect == 0.0 && extras->minProb == 0.0) + return; + +// more filtering +filterItems(track, eqtlIncludeFilter, "include"); +//uglyf(", items after filter: %d\n", slCount(track->items)); } static char *gtexEqtlClusterItemName(struct track *track, void *item) /* Load all items (and motifs if table is present) in window */ { -struct gtexEqtlCluster *cluster = (struct gtexEqtlCluster *)item; +struct gtexEqtlCluster *eqtl = (struct gtexEqtlCluster *)item; struct dyString *ds = dyStringNew(0); -if (cluster->expCount == 1) +if (eqtl->expCount == 1) { - dyStringPrintf(ds, "%s in %s", cluster->target, cluster->expNames[0]); + dyStringPrintf(ds, "%s in %s", eqtl->target, eqtl->expNames[0]); } else { - dyStringPrintf(ds, "%s in %d tissues", cluster->target, cluster->expCount); + int i, included; + for (i=0, included=0; iexpCount; i++) + if (!isExcludedTissue(eqtl, i)) + included++; + dyStringPrintf(ds, "%s in %d tissues", eqtl->target, included); } return dyStringCannibalize(&ds); } static Color gtexEqtlClusterItemColor(struct track *track, void *item, struct hvGfx *hvg) /* Color by highest effect in list (blue -, red +), with brighter for higher effect (teal, fuschia) */ { -struct gtexEqtlCluster *cluster = (struct gtexEqtlCluster *)item; +struct gtexEqtlCluster *eqtl = (struct gtexEqtlCluster *)item; double maxEffect = 0.0; int i; -for (i=0; iexpCount; i++) +for (i=0; iexpCount; i++) { - double effect = cluster->expScores[i]; + if (isExcludedTissue(eqtl, i)) + continue; + double effect = eqtl->expScores[i]; if (fabs(effect) > fabs(maxEffect)) maxEffect = effect; } double cutoff = 2.0; if (maxEffect < 0.0) { /* down-regulation displayed as blue */ if (maxEffect < 0.0 - cutoff) return MG_CYAN; return MG_BLUE; } /* up-regulation displayed as red */ if (maxEffect > cutoff) return MG_MAGENTA; return MG_RED; } -static void gtexEqtlClusterMapItem(struct track *tg, struct hvGfx *hvg, void *item, char *itemName, +static void gtexEqtlClusterMapItem(struct track *track, struct hvGfx *hvg, void *item, char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height) /* Create a map box on item and label with list of tissues with colors and effect size */ { char *title = itemName; //uglyf("
title: %s\n", title); -if (tg->limitedVis != tvDense) +if (track->limitedVis != tvDense) { // construct list of tissues with colors and effect sizes for mouseover struct gtexEqtlCluster *eqtl = (struct gtexEqtlCluster *)item; - //struct gtexEqtlClusterTrack *extras = (struct gtexEqtlClusterTrack *)tg->extraUiData; + //struct gtexEqtlClusterTrack *extras = (struct gtexEqtlClusterTrack *)track->extraUiData; //struct hash *tissueHash = extras->tissueHash; struct dyString *ds = dyStringNew(0); dyStringPrintf(ds, "%s/%s: ", eqtl->name, eqtl->target); int i; for (i=0; iexpCount; i++) { + if (isExcludedTissue(eqtl, i)) + continue; double effect= eqtl->expScores[i]; dyStringPrintf(ds, "%s(%s%0.2f)%s", eqtl->expNames[i], effect < 0 ? "" : "+", effect, i < eqtl->expCount - 1 ? ", " : ""); //struct gtexTissue *tis = (struct gtexTissue *)hashFindVal(tissueHash, eqtl->expNames[i]); //unsigned color = tis ? tis->color : 0; // BLACK //char *name = tis ? tis->name : "unknown"; //#dyStringPrintf(ds,"*%s%s%0.2f\n", //color, name, effect < 0 ? "" : "+", effect); } title = dyStringCannibalize(&ds); } //uglyf("
title2: %s\n", title); -genericMapItem(tg, hvg, item, title, itemName, start, end, x, y, width, height); +genericMapItem(track, hvg, item, title, itemName, start, end, x, y, width, height); } void gtexEqtlClusterMethods(struct track *track) /* BED5+5 with target, expNames,expScores, expProbs */ { track->loadItems = gtexEqtlClusterLoadItems; track->itemName = gtexEqtlClusterItemName; track->itemColor = gtexEqtlClusterItemColor; track->mapItem = gtexEqtlClusterMapItem; }