6033d2468a21ebbbd55dc6ac52fbc5229a1dd119 kate Mon Jul 20 09:59:24 2015 -0700 Mouseover improvements. refs #15645 diff --git src/hg/hgTracks/gtexTracks.c src/hg/hgTracks/gtexTracks.c index b30faee..c883554 100644 --- src/hg/hgTracks/gtexTracks.c +++ src/hg/hgTracks/gtexTracks.c @@ -97,90 +97,132 @@ } static int valToY(double val, double maxVal, int height) /* Convert a value from 0 to maxVal to 0 to height-1 */ { double scaled = val/maxVal; int y = scaled * (height-1); return height - 1 - y; } struct gtexGeneExtras { double maxExp; }; -struct rgbColor *getGtexTissueColors() -/* Get RGB colors from tissue table */ + +/* Cache tissue metadata */ + +struct gtexTissue *getGtexTissues() +/* Get tissue metadata from database */ +{ +static struct gtexTissue *gtexTissues = NULL; +if (gtexTissues == NULL) { char query[1024]; struct sqlConnection *conn = sqlConnect("hgFixed"); sqlSafef(query, sizeof(query), "select * from gtexTissue order by id"); -struct gtexTissue *tissues = gtexTissueLoadByQuery(conn, query); + gtexTissues = gtexTissueLoadByQuery(conn, query); + } +return gtexTissues; +} + +struct rgbColor *getGtexTissueColors() +/* Get RGB colors from tissue table */ +{ +struct gtexTissue *tissues = getGtexTissues(); struct gtexTissue *tissue = NULL; int count = slCount(tissues); struct rgbColor *colors; AllocArray(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)}; //colors[i] = mgColorIxToRgb(NULL, tissue->color); i++; } -sqlDisconnect(&conn); return colors; } +static int gtexGraphWidth(struct gtexGeneBed *gtex) +/* Width of GTEx graph in pixels */ +{ +int barWidth = gtexBarWidth(); +int padding = gtexGraphPadding(); +int count = gtex->expCount; +return (barWidth * count) + (padding * (count-1)); +} + +static int gtexGraphX(struct gtexGeneBed *gtex) +/* Locate graph on X, relative to viewport. Return -1 if it won't fit */ +{ +int start = max(gtex->chromStart, winStart); +int end = min(gtex->chromEnd, winEnd); +if (start > end) + return -1; +double scale = scaleForWindow(insideWidth, winStart, winEnd); +int x1 = round((start - winStart) * scale); +int x2 = round((end - winStart) * scale); +int width = gtexGraphWidth(gtex); +if (x1 + width > x2) + return -1; +return x1; +} + static void gtexGeneDrawAt(struct track *tg, void *item, struct hvGfx *hvg, int xOff, int y, double scale, MgFont *font, Color color, enum trackVisibility vis) { struct gtexGeneBed *geneBed = item; //warn("item: %s, xOff=%d\n", geneBed->name, xOff); if (vis != tvFull && vis != tvPack) { initGeneColors(hvg); // Color using transcriptClass if (geneBed->transcriptClass == NULL) color = statusColors.unknown; if (sameString(geneBed->transcriptClass, "coding")) color = statusColors.coding; else if (sameString(geneBed->transcriptClass, "nonCoding")) color = statusColors.nonCoding; else if (sameString(geneBed->transcriptClass, "problem")) color = statusColors.problem; else color = statusColors.unknown; bedDrawSimpleAt(tg, item, hvg, xOff, y, scale, font, color, vis); return; } int i; int expCount = geneBed->expCount; double maxExp = ((struct gtexGeneExtras *)tg->extraUiData)->maxExp; struct rgbColor lineColor = {.r=0}; int lineColorIx = hvGfxFindColorIx(hvg, lineColor.r, lineColor.g, lineColor.b); int heightPer = tg->heightPer; -int start = max(geneBed->chromStart, winStart); +////int start = max(geneBed->chromStart, winStart); + //int geneEnd = min(geneBed->chromEnd, winEnd); //int width = expCount * (BAR_WIDTH + PADDING); //int end = min(expCount*(BAR_WIDTH + PADDING), winEnd); //if (start > end) //return; -int x1 = round((start-winStart)*scale) + xOff; +////int x1 = round((start-winStart)*scale) + xOff; +int x1 = gtexGraphX(geneBed) + xOff; +//warn("gtexGeneDrawAt: x1=%d, labelWidth=%d. ", + //x1, mgFontStringWidth(font, geneBed->name)); //int x2 = round((e-winStart)*scale) + xOff; int yBase = valToY(0, maxExp, heightPer) + y; //int yZero = yBase - 5; //int firstX = x1; int barWidth = gtexBarWidth(); int graphPadding = gtexGraphPadding(); char *colorScheme = cartUsualStringClosestToHome(cart, tg->tdb, FALSE, GTEX_COLORS, GTEX_COLORS_DEFAULT); struct rgbColor *colors; if (sameString(colorScheme, GTEX_COLORS_GTEX)) { // retrieve from table // TODO: cache this @@ -210,64 +252,104 @@ hvGfxBox(hvg, x1, yMedian, barWidth, yBase - yMedian, fillColorIx); else hvGfxOutlinedBox(hvg, x1, yMedian, barWidth, yBase - yMedian, fillColorIx, lineColorIx); //warn("x1=%d, yMedian=%d, height=%d\n", x1, yMedian, yBase-yMedian); x1 = x1 + barWidth + graphPadding; } // underline gene extent //hvGfxBox(hvg, firstX, yBase, round((geneEnd - start)*scale), 3, lineColorIx); // TODO: replace with cached table hash //char *tissueTable = "gtexTissue"; //struct sqlConnection *conn = hAllocConn("hgFixed"); //hFreeConn(&conn); } +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) */ +{ +//uglyf("map item: itemName=%s, mapItemName=%s, start=%d, end=%d, x=%d, y=%d, width=%d, height=%d, insideX=%d", + //itemName, mapItemName, start, end, x, y, width, height, insideX); +struct gtexTissue *tissues = getGtexTissues(); +struct gtexTissue *tissue = NULL; +struct gtexGeneBed *gtex = item; +int barWidth = gtexBarWidth(); +int padding = gtexGraphPadding(); +int heightPer = tg->heightPer; +double maxExp = ((struct gtexGeneExtras *)tg->extraUiData)->maxExp; +int i = 0; +//int start1 = max(start, winStart); +// TODO: support reverse display (hvg->rc) +//double scale = scaleForWindow(width, start, end); +//int x1 = round((start-winStart)*scale) + x; + +// skip over label. TODO: check w/ different modes, and look for a better way +// map box on label +int labelWidth = mgFontStringWidth(tl.font, gtex->name) + 3; +mapBoxHc(hvg, start, end, x, y, labelWidth, height, tg->track, mapItemName, mapItemName); +int x1 = x + labelWidth; +for (tissue = tissues; tissue != NULL; tissue = tissue->next, i++) + { + //hvGfxBox(hvg, x1, yMedian, barWidth, yBase - yMedian, fillColorIx); + double expScore = gtex->expScores[i]; + int yBase = valToY(0, maxExp, heightPer) + y; + int yMedian = valToY(expScore, maxExp, heightPer) + y; + int height = yBase - yMedian; + // TODO: call genericMapItem + //genericMapItem(tg, hvg, item, itemName, tissue->description, start, end, x1, y, barWidth, height); + mapBoxHc(hvg, start, end, x1, yMedian, barWidth, height, tg->track, mapItemName, tissue->description); + //uglyf("id=%d, mapItemName= %s, start=%d, end=%d, x1=%d, y=%d (expScore=%.2f, yMedian=%d, yBase=%d), height=%d. ", + //i, mapItemName, start, end, x1, y1, expScore, yMedian, yBase, height); + x1 = x1 + barWidth + padding; + } +} + static struct gtexGeneBed *loadGtexGeneBed(char **row) { return gtexGeneBedLoad(row); } static void gtexGeneLoadItems(struct track *track) { bedLoadItem(track, track->table, (ItemLoader)loadGtexGeneBed); double maxExp = 0.0; int i; struct gtexGeneBed *geneBed; for (geneBed = track->items; geneBed != NULL; geneBed = geneBed->next) for (i=0; i<geneBed->expCount; i++) maxExp = (geneBed->expScores[i] > maxExp ? geneBed->expScores[i] : maxExp); struct gtexGeneExtras *extras; AllocVar(extras); extras->maxExp = maxExp; track->extraUiData = extras; } - static int gtexGeneItemHeight(struct track *track, void *item) { if ((item == NULL) || (track->visibility == tvSquish) || (track->visibility == tvDense)) return 0; return gtexGraphHeight(); } static int gtexTotalHeight(struct track *track, enum trackVisibility vis) /* Figure out total height of track */ { int height; if (track->visibility == tvSquish || track->visibility == tvDense) height = 10; else height = gtexGraphHeight(); return tgFixedTotalHeightOptionalOverflow(track, vis, height, height, FALSE); } void gtexGeneMethods(struct track *track) { track->drawItemAt = gtexGeneDrawAt; track->loadItems = gtexGeneLoadItems; +track->mapItem = gtexGeneMapItem; track->itemHeight = gtexGeneItemHeight; track->totalHeight = gtexTotalHeight; }