f4aba74550dea6d8548ba891cb9d057eaf6de43e kate Wed Mar 22 12:30:24 2017 -0700 Fix bogus color cacheing. Its now per-track diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c index 31a2434..d7e5a9e 100644 --- src/hg/hgTracks/gtexTracks.c +++ src/hg/hgTracks/gtexTracks.c @@ -36,31 +36,35 @@ struct gtexGeneExtras /* Track info */ { char *version; /* Suffix to table name, e.g. 'V6' */ boolean codingOnly; /* User filter to limit display to coding genes */ boolean showExons; /* Show gene model exons */ boolean noWhiteout; /* Suppress whiteout of graph background (allow highlight, blue lines) */ enum geneLabelStyle labelStyle; /* Show gene symbol, accession, or both */ double maxMedian; /* Maximum median rpkm for all tissues */ boolean isComparison; /* Comparison of two sample sets (e.g. male/female). */ boolean isDifference; /* True if comparison is shown as a single difference graph. False if displayed as two graphs, one oriented downward */ char *graphType; /* Additional info about graph (e.g. type of comparison graph */ struct rgbColor *colors; /* Color palette for tissues */ boolean doLogTransform; /* Log10(x+1) */ - struct gtexTissue *tissues; /* Cache tissue names, descriptions */ + struct gtexTissue *tissues; /* Tissue names, descriptions */ + int tissueCount; /* Tissue count - derived from above */ + char **tissueNames; /* Tissue names by id - derived from above */ + char **tissueLabels; /* Tissue labels by id - derived from above */ + char **tissueDescriptions; /* Tissue descriptions by id - derived from above */ struct hash *tissueFilter; /* For filter. NULL out excluded tissues */ }; struct gtexGeneInfo /* GTEx gene model, names, and expression medians */ { struct gtexGeneInfo *next; /* Next in singly linked list */ struct gtexGeneBed *geneBed;/* Gene name, id, type, exp count and medians from BED table */ struct genePred *geneModel; /* Gene structure from model table */ char *label; /* Name, accession, or both */ char *description; /* Gene description */ double *medians1; /* Computed medians */ double *medians2; /* Computed medians for comparison (inverse) graph */ int height; /* Item height in pixels */ @@ -107,134 +111,136 @@ char *geneClass = gtexGeneClass(geneBed); if (geneClass == NULL) return statusColors.unknown; if (sameString(geneClass, "coding")) return statusColors.coding; if (sameString(geneClass, "nonCoding")) return statusColors.nonCoding; if (sameString(geneClass, "pseudo")) return statusColors.pseudo; return statusColors.unknown; } /***********************************************/ /* Cache tissue info */ -struct gtexTissue *getTissues(char *version) +struct gtexTissue *getTissues(struct track *tg, char *version) /* Get and cache tissue metadata from database */ { -static struct gtexTissue *gtexTissues = NULL; - -if (!gtexTissues) - gtexTissues = gtexGetTissues(version); -return gtexTissues; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (!extras->tissues) + extras->tissues = gtexGetTissues(version); +return extras->tissues; } -int getTissueCount(char *version) +int getTissueCount(struct track *tg, char *version) /* Get and cache the number of tissues in GTEx tissue table */ { -static int tissueCount = 0; - -if (!tissueCount) - tissueCount = slCount(getTissues(version)); -return tissueCount; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (!extras->tissueCount) + extras->tissueCount = slCount(getTissues(tg, version)); +return extras->tissueCount; } -char *getTissueName(int id, char *version) +char *getTissueName(struct track *tg, int id, char *version) /* Get tissue name from id, cacheing */ { -static char **tissueNames = NULL; struct gtexTissue *tissue; -int count = getTissueCount(version); -if (!tissueNames) +int count = getTissueCount(tg, version); +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (!extras->tissueNames) { - struct gtexTissue *tissues = getTissues(version); - AllocArray(tissueNames, count); + struct gtexTissue *tissues = getTissues(tg, version); + AllocArray(extras->tissueNames, count); for (tissue = tissues; tissue != NULL; tissue = tissue->next) - tissueNames[tissue->id] = cloneString(tissue->name); + extras->tissueNames[tissue->id] = cloneString(tissue->name); } if (id >= count) errAbort("GTEx tissue table problem: can't find id %d\n", id); -return tissueNames[id]; +return extras->tissueNames[id]; } -char *getTissueDescription(int id, char *version) +char *getTissueDescription(struct track *tg, int id, char *version) /* Get tissue description from id, cacheing */ { -static char **tissueDescriptions = NULL; struct gtexTissue *tissue; -int count = getTissueCount(version); -if (!tissueDescriptions) +int count = getTissueCount(tg, version); +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (!extras->tissueDescriptions) { - struct gtexTissue *tissues = getTissues(version); - AllocArray(tissueDescriptions, count); + struct gtexTissue *tissues = getTissues(tg, version); + AllocArray(extras->tissueDescriptions, count); for (tissue = tissues; tissue != NULL; tissue = tissue->next) - tissueDescriptions[tissue->id] = cloneString(tissue->description); + extras->tissueDescriptions[tissue->id] = cloneString(tissue->description); } if (id >= count) errAbort("GTEx tissue table problem: can't find id %d\n", id); -return tissueDescriptions[id]; +return extras->tissueDescriptions[id]; } -struct rgbColor *getGtexTissueColors(char *version) +struct rgbColor *getGtexTissueColors(struct track *tg, char *version) /* Get RGB colors from tissue table */ { -struct gtexTissue *tissues = getTissues(version); +struct gtexTissue *tissues = getTissues(tg, version); struct gtexTissue *tissue = NULL; -int count = slCount(tissues); -struct rgbColor *colors; -AllocArray(colors, count); +int count = getTissueCount(tg, version); +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; +if (!extras->colors) + { + AllocArray(extras->colors, count); int i = 0; for (tissue = tissues; tissue != NULL; tissue = tissue->next) { // TODO: reconcile - colors[i] = (struct rgbColor){.r=COLOR_32_BLUE(tissue->color), .g=COLOR_32_GREEN(tissue->color), .b=COLOR_32_RED(tissue->color)}; + extras->colors[i] = (struct rgbColor){.r=COLOR_32_BLUE(tissue->color), .g=COLOR_32_GREEN(tissue->color), .b=COLOR_32_RED(tissue->color)}; //colors[i] = mgColorIxToRgb(NULL, tissue->color); i++; } -return colors; + } +return extras->colors; } /*****************************************************************/ /* Load sample data, gene info, and anything else needed to draw */ static struct hash *loadGeneModels(char *table) /* Load gene models from table */ { struct sqlConnection *conn = hAllocConn(database); struct sqlResult *sr; char **row; int rowOffset; sr = hRangeQuery(conn, table, chromName, winStart, winEnd, NULL, &rowOffset); struct hash *modelHash = newHash(0); struct genePred *model = NULL; while ((row = sqlNextRow(sr)) != NULL) { model = genePredLoad(row+rowOffset); hashAdd(modelHash, model->name, model); } sqlFreeResult(&sr); hFreeConn(&conn); return modelHash; } -static void loadComputedMedians(struct gtexGeneInfo *geneInfo, struct gtexGeneExtras *extras) +static void loadComputedMedians(struct track *tg, struct gtexGeneInfo *geneInfo) /* Compute medians based on graph type. Returns a list of 2 for comparison graph types */ { struct gtexGeneBed *geneBed = geneInfo->geneBed; int expCount = geneBed->expCount; +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; if (extras->isComparison) { // create two score hashes, one for each sample subset struct hash *scoreHash1 = hashNew(0), *scoreHash2 = hashNew(0); struct sqlConnection *conn = hAllocConn("hgFixed"); char query[1024]; char **row; sqlSafef(query, sizeof(query), "select gtexSampleData.sample, gtexDonor.gender, gtexSampleData.tissue, gtexSampleData.score from gtexSampleData, gtexSample, gtexDonor where gtexSampleData.geneId='%s' and gtexSampleData.sample=gtexSample.sampleId and gtexSample.donor=gtexDonor.name", geneBed->geneId); struct sqlResult *sr = sqlGetResult(conn, query); while ((row = sqlNextRow(sr)) != NULL) { char gender = *row[1]; // TODO: generalize for other comparison graphs (this code just for M/F comparison) struct hash *scoreHash = ((gender == 'F') ? scoreHash1 : scoreHash2); char *tissue = cloneString(row[2]); @@ -248,34 +254,34 @@ hashAdd(scoreHash, tissue, score); } sqlFreeResult(&sr); hFreeConn(&conn); // get tissue medians for each sample subset double *medians1; double *medians2; AllocArray(medians1, expCount); AllocArray(medians2, expCount); int i; for (i=0; i<geneBed->expCount; i++) { //medians1[i] = -1, medians2[i] = -1; // mark missing tissues ? struct slDouble *scores; - scores = hashFindVal(scoreHash1, getTissueName(i, extras->version)); + scores = hashFindVal(scoreHash1, getTissueName(tg, i, extras->version)); if (scores) medians1[i] = slDoubleMedian(scores); - scores = hashFindVal(scoreHash2, getTissueName(i, extras->version)); + scores = hashFindVal(scoreHash2, getTissueName(tg, i, extras->version)); if (scores) medians2[i] = slDoubleMedian(scores); } if (extras->isDifference) { for (i=0; i<geneBed->expCount; i++) { if (medians1[i] >= medians2[i]) { medians1[i] -= medians2[i]; medians2[i] = 0; } else { medians2[i] -= medians1[i]; @@ -309,31 +315,31 @@ if (winSize < WIN_MAX_GRAPH) return MAX_GENE_BOX_HEIGHT; else if (winSize < WIN_MED_GRAPH) return MED_GENE_BOX_HEIGHT; else return MIN_GENE_BOX_HEIGHT; } static int gtexGeneItemHeight(struct track *tg, void *item); static void filterTissues(struct track *tg) /* Check cart for tissue selection. NULL out unselected tissues in tissue list */ { struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; struct gtexTissue *tis = NULL; -extras->tissues = getTissues(extras->version); +extras->tissues = getTissues(tg, extras->version); extras->tissueFilter = hashNew(0); if (cartListVarExistsAnyLevel(cart, tg->tdb, FALSE, GTEX_TISSUE_SELECT)) { struct slName *selectedValues = cartOptionalSlNameListClosestToHome(cart, tg->tdb, FALSE, GTEX_TISSUE_SELECT); if (selectedValues != NULL) { struct slName *name; for (name = selectedValues; name != NULL; name = name->next) hashAdd(extras->tissueFilter, name->name, name->name); return; } } /* no filter */ for (tis = extras->tissues; tis != NULL; tis = tis->next) @@ -432,33 +438,34 @@ /* Get geneBeds (names and all-sample tissue median scores) in range */ char *filter = getScoreFilterClause(cart, tg->tdb, NULL); bedLoadItemWhere(tg, tg->table, filter, (ItemLoader)gtexGeneBedLoad); /* Create geneInfo items with BED and geneModels */ struct gtexGeneInfo *geneInfo = NULL, *list = NULL; struct gtexGeneBed *geneBed = (struct gtexGeneBed *)tg->items; /* Load tissue colors: GTEx or rainbow */ #ifdef COLOR_SCHEME char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS, GTEX_COLORS_DEFAULT); #else char *colorScheme = GTEX_COLORS_DEFAULT; #endif + if (sameString(colorScheme, GTEX_COLORS_GTEX)) { - extras->colors = getGtexTissueColors(extras->version); + extras->colors = getGtexTissueColors(tg, extras->version); } else { if (geneBed) { int expCount = geneBed->expCount; extras->colors = getRainbow(&saturatedRainbowAtPos, expCount); } } filterTissues(tg); while (geneBed != NULL) { if (extras->codingOnly && !gtexGeneIsCoding(geneBed)) { @@ -503,31 +510,31 @@ // also strip 'homo sapiens' prefix #define SPECIES_PREFIX "Homo sapiens " if (startsWith(SPECIES_PREFIX, desc)) desc += strlen(SPECIES_PREFIX); geneInfo->description = desc; } else geneInfo->description = geneInfo->geneBed->name; slAddHead(&list, geneInfo); geneBed = geneBed->next; geneInfo->geneBed->next = NULL; if (extras->isComparison && (tg->visibility == tvFull || tg->visibility == tvPack)) // compute medians based on configuration (comparisons, and later, filters) - loadComputedMedians(geneInfo, extras); + loadComputedMedians(tg, geneInfo); geneInfo->height = gtexGeneItemHeight(tg, geneInfo); } slReverse(&list); tg->items = list; } /***********************************************/ /* Draw */ /* Bargraph layouts for three window sizes */ #define WIN_MAX_GRAPH 50000 #define MAX_GRAPH_HEIGHT 175 #define MAX_BAR_WIDTH 5 #define MAX_GRAPH_PADDING 2 @@ -651,31 +658,31 @@ return valToHeight(useVal, useMax, gtexMaxGraphHeight(), doLogTransform); } static int gtexGeneGraphHeight(struct track *tg, struct gtexGeneInfo *geneInfo, boolean doTop) /* Determine height in pixels of graph. This will be the box for tissue with highest expression If doTop is false, compute height of bottom graph of comparison */ { struct gtexGeneBed *geneBed = geneInfo->geneBed; struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; int i; double maxExp = 0.0; int expCount = geneBed->expCount; double expScore; for (i=0; i<expCount; i++) { - if (!filterTissue(tg, getTissueName(i, extras->version))) + if (!filterTissue(tg, getTissueName(tg, i, extras->version))) continue; if (doTop) expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); else expScore = geneInfo->medians2[i]; maxExp = max(maxExp, expScore); } double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT); double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; return valToClippedHeight(maxExp, maxMedian, viewMax, gtexMaxGraphHeight(), extras->doLogTransform); } static void drawGraphBox(struct track *tg, struct gtexGeneInfo *geneInfo, struct hvGfx *hvg, int x, int y) /* Draw white background for graph */ @@ -962,48 +969,48 @@ if (tg->limitedVis == tvDense) { genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height); return; } struct gtexGeneInfo *geneInfo = item; struct gtexGeneBed *geneBed = geneInfo->geneBed; struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; int geneStart = geneBed->chromStart; int geneEnd = geneBed->chromEnd; if (tg->limitedVis == tvSquish) { int tisId = maxTissueForGene(geneBed); char *maxTissue = ""; if (tisId > 1) - maxTissue = getTissueDescription(tisId, extras->version); + maxTissue = getTissueDescription(tg, tisId, extras->version); char buf[128]; safef(buf, sizeof buf, "%s %s", geneBed->name, maxTissue); int x1, x2; getItemX(geneStart, geneEnd, &x1, &x2); int width = max(1, x2-x1); mapBoxHc(hvg, geneStart, geneEnd, x1, y, width, height, tg->track, mapItemName, buf); return; } int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); // label int yZero = topGraphHeight + y - 1; // yZero is bottom of graph int x1 = insideX; // add maps to tissue bars in expresion graph -struct gtexTissue *tissues = getTissues(extras->version); +struct gtexTissue *tissues = getTissues(tg, extras->version); struct gtexTissue *tissue = NULL; int barWidth = gtexBarWidth(); int padding = gtexGraphPadding(); double maxMedian = ((struct gtexGeneExtras *)tg->extraUiData)->maxMedian; int graphX = gtexGraphX(geneBed); if (graphX < 0) return; // x1 is at left of graph x1 = insideX + graphX; if (geneInfo->medians2) { // skip over labels in comparison graphs