51609277effd21687e81efe1d1e2c58ef21328e8 kent Sat Jan 30 09:06:31 2021 -0800 Got this to work with the table in a tsv file and with graphical bars as part of the table. I'm stopping development on this piece since I think I can integrate it into hgc (in fact I have) and into hgTrackUi rather than needing a separate CGI. Still a lot of refactoring to do. I'll probably be moving this module into oneShot soon. No need to review. It has served it's purpose, and the code here will be redistributed and libified. diff --git src/hg/hgFacetedBars/hgFacetedBars.c src/hg/hgFacetedBars/hgFacetedBars.c index ab18573..3876b1f 100644 --- src/hg/hgFacetedBars/hgFacetedBars.c +++ src/hg/hgFacetedBars/hgFacetedBars.c @@ -3,30 +3,31 @@ #include "common.h" #include "linefile.h" #include "hash.h" #include "options.h" #include "jksql.h" #include "htmshell.h" #include "web.h" #include "cheapcgi.h" #include "cart.h" #include "hui.h" #include "udc.h" #include "knetUdc.h" #include "genbank.h" #include "tablesTables.h" #include "facetField.h" +#include "sqlNum.h" /* Global Variables */ struct cart *cart; /* CGI and other variables */ struct hash *oldVars = NULL; char *database = NULL; char *genome = NULL; struct facetedTable /* Help manage a faceted table */ { struct facetedTable *next; char *name; /* Name of file or database table */ char *varPrefix; /* Prefix used on variables */ }; @@ -131,87 +132,164 @@ char selListVar[256]; safef(selListVar, sizeof(selListVar), "%s_facet_selList", ft->varPrefix); char *selectedFacetValues=cartUsualString(cart, selListVar, ""); struct facetField *selList = deLinearizeFacetValString(selectedFacetValues); selectedListFacetValUpdate(&selList, selFieldName, selFieldVal, selOp); char *newSelectedFacetValues = linearizeFacetVals(selList); cartSetString(cart, selListVar, newSelectedFacetValues); facetedTableRemoveOpVars(ft, cart); } return TRUE; } else return FALSE; } +struct wrapContext +/* Context used by various wrappers. */ + { + int nameIx; /* First col by convention is name */ + int countIx; /* Index of count in row */ + int meanIx; /* The field that has total read count */ + int colorIx; /* Index of color in row */ + double maxMean;/* Maximum of any total value */ + }; + +void wrapMean(struct fieldedTable *table, struct fieldedRow *row, + char *field, char *val, char *shortVal, void *context) +/* Write out wrapper draws a SVG bar*/ +{ +struct wrapContext *wc = context; +char *color = "#000000"; +int colorIx = wc->colorIx; +if (colorIx >= 0) + color = row->row[colorIx]; +double mean = sqlDouble(val); +int width = 500, height = 13; // These are units of ~2010 pixels or something +double barWidth = (double)width*mean/wc->maxMean; +printf("", barWidth, height); +printf("", + barWidth, height, color); +printf(""); +printf(" %6.2f", mean); +} + +double fieldedTableMaxInCol(struct fieldedTable *table, int colIx) +/* Figure out total and count columns from context and use them to figure + * out maximum mean value */ +{ +boolean firstTime = TRUE; +double max = 0.0; +struct fieldedRow *fr; +for (fr = table->rowList; fr != NULL; fr = fr->next) + { + double val = sqlDouble(fr->row[colIx]); + if (firstTime) + { + max = val; + firstTime = FALSE; + } + else if (max < val) + max = val; + } +return max; +} + +#ifdef OLD +double calcMaxMean(struct fieldedTable *table, struct wrapContext *context) +/* Go through text table figureing out mean for each row based on + * context fields. Return max of the means */ +{ +boolean firstTime = TRUE; +double max = 0.0; +struct fieldedRow *fr; +int countIx = context->countIx; +int totalIx = context->totalIx; +for (fr = table->rowList; fr != NULL; fr = fr->next) + { + double val = sqlDouble(fr->row[totalIx])/sqlDouble(fr->row[countIx]); + if (firstTime) + { + max = val; + firstTime = FALSE; + } + else if (max < val) + max = val; + } +return max; +} +#endif /* OLD */ void doBody() { /* Fake up a 'track' for development */ char *trackName = "cellFacetsJk1"; struct sqlConnection *conn = sqlConnect(database); struct hash *emptyHash = hashNew(0); +struct hash *wrapperHash = hashNew(0); struct facetedTable *ft = facetedTableNew("the original", trackName); /* Write out html to pull in the other files we use. */ facetedTableWebInit(); /* Working within a form we save context */ printf("
\n"); cartSaveSession(cart); /* Set up url that has enough context to get back to us. This is very much a work in * progress. */ char returnUrl[PATH_LEN*2]; safef(returnUrl, sizeof(returnUrl), "../cgi-bin/hgFacetedBars?%s", cartSidUrlString(cart) ); -/* Put up the big faceted search table */ -printf("
\n"); +/* Put up the big faceted search table in a new div */ + +/* Load up table from tsv file */ char *statsFileName = "/gbdb/hg38/bbi/singleCellMerged/barChart.stats"; -char *requiredStatsFields[] = {"cluster","count","mean","organ","cell_class","stage","cell_type"}; +char *requiredStatsFields[] = {"cluster","count","organ","cell_class","stage","cell_type"}; struct fieldedTable *table = fieldedTableFromTabFile(statsFileName, statsFileName, requiredStatsFields, ArraySize(requiredStatsFields)); + +/* Update facet selections from users input if any */ facetedTableUpdateOnFacetClick(ft, cart); -/* Look up sel val in cart */ +/* Do facet selection calculations */ char *selList = facetedTableSelList(ft, cart); struct facetField *ffArray[table->fieldCount]; -int selCount = 0; -facetFieldsFromFieldedTable(table, selList, ffArray, &selCount); -// uglyf("%d of %d selected in facets", selCount, table->rowCount); -webFilteredFieldedTable(cart, table, - "count,cluster,mean", returnUrl, trackName, - 32, emptyHash, NULL, +struct fieldedTable *selected = facetFieldsFromFieldedTable(table, selList, ffArray); + + +/* Set up wrappers for some of output fields */ +struct wrapContext context = {.nameIx = 0, + .countIx = fieldedTableFindFieldIx(table, "count"), + .meanIx = fieldedTableFindFieldIx(table, "mean_total"), + .colorIx = fieldedTableFindFieldIx(table, "color"), + }; +context.maxMean = fieldedTableMaxInCol(table, context.meanIx); + +/* Put up faceted search and table of visible fields. */ +hashAdd(wrapperHash, "mean_total", wrapMean); +webFilteredFieldedTable(cart, selected, + "count,cluster,mean_total", returnUrl, trackName, + 32, wrapperHash, &context, FALSE, NULL, - table->rowCount, 7, + selected->rowCount, 7, NULL, emptyHash, ffArray, "organ,cell_class,stage,cell_type", NULL); -#ifdef OLD -webFilteredSqlTable(cart, conn, - "organ,cell_class,cell_type", trackName, "", - returnUrl, trackName, 32, - emptyHash, NULL, - FALSE, NULL, 50, 7, emptyHash, "organ,cell_class,stage,cell_type", - NULL); -#endif /* OLD */ -printf("
\n"); - - /* Clean up and go home. */ printf("
\n"); hashFree(&emptyHash); sqlDisconnect(&conn); } void doMiddle(struct cart *theCart) /* Set up globals and make web page */ { /* Set some major global variable and attach us to current genome and DB. */ cart = theCart; getDbAndGenome(cart, &database, &genome, oldVars); initGenbankTableNames(database); /* Set udcTimeout from cart */