0f09add63f6f06980b54fe6b18881d38747db60b kate Thu Nov 19 12:20:50 2015 -0800 Add difference graph feature to GTEx track. refs #15645 diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c index 03439e5..f6fbbbc 100644 --- src/hg/hgTracks/gtexTracks.c +++ src/hg/hgTracks/gtexTracks.c @@ -11,32 +11,33 @@ #include "gtexGeneBed.h" #include "gtexTissue.h" #include "gtexTissueData.h" #include "gtexUi.h" // TODO: move spaceSaver code to simpleTracks #include "spaceSaver.h" // NOTE: Sections to change for multi-region (vertical slice) display // are marked with #ifdef MULTI_REGION. WARNING: These sections // are a bit out-of-date (refer to #ifndef MULTI code when integrating) struct gtexGeneExtras /* Track info */ { double maxMedian; /* Maximum median rpkm for all tissues */ - boolean isComparison; /* Comparison of two sample sets (e.g. male/female). - Displayed as two graphs, one oriented downward */ + 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 */ }; struct gtexGeneInfo /* GTEx gene model, names, and expression medians */ { struct gtexGeneInfo *next; /* Next in singly linked list */ struct gtexGeneBed *geneBed;/* Gene name, id, canonical transcript, exp count and medians from BED table */ struct genePred *geneModel; /* Gene structure from model table */ double *medians1; /* Computed medians */ double *medians2; /* Computed medians for comparison (inverse) graph */ int height; /* Item height in pixels */ }; @@ -208,53 +209,73 @@ 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)); if (scores) medians1[i] = slDoubleMedian(scores); scores = hashFindVal(scoreHash2, getTissueName(i)); 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]; + medians1[i] = 0; + } + } + } geneInfo->medians1 = medians1; geneInfo->medians2 = medians2; + } else { // TODO: compute median for single graph based on filtering of sample set } } static int gtexGeneItemHeight(struct track *tg, void *item); static void gtexGeneLoadItems(struct track *tg) /* Load method for track items */ { /* Get track UI info */ struct gtexGeneExtras *extras; AllocVar(extras); tg->extraUiData = extras; char *samples = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_SAMPLES, GTEX_SAMPLES_DEFAULT); extras->graphType = cloneString(samples); if (sameString(samples, GTEX_SAMPLES_COMPARE_SEX)) extras->isComparison = TRUE; +char *comparison = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COMPARISON_DISPLAY, + GTEX_COMPARISON_DEFAULT); +extras->isDifference = sameString(comparison, GTEX_COMPARISON_DIFF) ? TRUE : FALSE; extras->maxMedian = gtexMaxMedianScore(NULL); /* Get geneModels in range */ //TODO: version the table name, move to lib char *modelTable = "gtexGeneModel"; struct hash *modelHash = loadGeneModels(modelTable); /* Get geneBeds (names and all-sample tissue median scores) in range */ bedLoadItem(tg, tg->table, (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 */ @@ -746,39 +767,53 @@ void gtexGeneDrawItems(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw GTEx gene graphs, which are of variable height so require custom layout in full * and pack modes */ { if (vis == tvDense || vis == tvSquish) genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); else if (vis == tvFull) gtexGeneDrawItemsFull(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); else if (vis == tvPack) genericDrawItems(tg, seqStart, seqEnd, hvg, xOff, yOff, width, font, color, vis); } +static char *tissueExpressionText(struct gtexTissue *tissue, double expScore, + boolean doLogTransform, char *qualifier) +/* Construct mouseover text for tissue graph */ +{ +static char buf[128]; +safef(buf, sizeof(buf), "%s (%.1f %s%s%sRPKM)", tissue->description, + doLogTransform ? log10(expScore+1.0) : expScore, + qualifier != NULL ? qualifier : "", + qualifier != NULL ? " " : "", + doLogTransform ? "log " : ""); +return buf; +} + static void gtexGeneMapItem(struct track *tg, 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 for each tissue (bar in the graph) or a single map for squish/dense modes */ { if (tg->visibility == tvDense || tg->visibility == tvSquish) { genericMapItem(tg, hvg, item, itemName, itemName, start, end, x, y, width, height); return; } +struct gtexGeneExtras *extras = (struct gtexGeneExtras *)tg->extraUiData; struct gtexTissue *tissues = getTissues(); struct gtexTissue *tissue = NULL; struct gtexGeneInfo *geneInfo = item; struct gtexGeneBed *geneBed = geneInfo->geneBed; 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 int x1 = insideX + graphX; if (geneInfo->medians2) @@ -789,41 +824,46 @@ int i = 0; boolean doLogTransform = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE, GTEX_LOG_TRANSFORM, GTEX_LOG_TRANSFORM_DEFAULT); int topGraphHeight = gtexGeneGraphHeight(tg, geneInfo, doLogTransform, TRUE); topGraphHeight = max(topGraphHeight, tl.fontHeight); // label int yZero = topGraphHeight + y - 1; // yZero is bottom of (top) graph double viewMax = (double)cartUsualIntClosestToHome(cart, tg->tdb, FALSE, GTEX_MAX_LIMIT, GTEX_MAX_LIMIT_DEFAULT); for (tissue = tissues; tissue != NULL; tissue = tissue->next, i++) { double expScore = (geneInfo->medians1 ? geneInfo->medians1[i] : geneBed->expScores[i]); int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexMaxGraphHeight(), doLogTransform); + char *qualifier = NULL; + if (extras->isComparison && extras->isDifference) + qualifier = "F-M"; mapBoxHc(hvg, start, end, x1, yZero-height, barWidth, height, tg->track, mapItemName, - tissue->description); + tissueExpressionText(tissue, expScore, doLogTransform, qualifier)); // add map box to comparison graph if (geneInfo->medians2) { double expScore = geneInfo->medians2[i]; int height = valToClippedHeight(expScore, maxMedian, viewMax, gtexMaxGraphHeight(), doLogTransform); int y = yZero + gtexGeneModelHeight() + gtexGeneMargin(); // y is top of bottom graph + if (extras->isComparison && extras->isDifference) + qualifier = "M-F"; mapBoxHc(hvg, start, end, x1, y, barWidth, height, tg->track, mapItemName, - tissue->description); + tissueExpressionText(tissue, expScore, doLogTransform, qualifier)); } x1 = x1 + barWidth + padding; } } static char *gtexGeneItemName(struct track *tg, void *item) /* Return gene name */ { struct gtexGeneInfo *geneInfo = (struct gtexGeneInfo *)item; struct gtexGeneBed *geneBed = geneInfo->geneBed; return geneBed->name; } static int gtexGeneHeight(void *item) {