038e590eac583c4253e53b234b365a4e842586c5 kent Sat Jan 30 09:02:52 2021 -0800 Initial implementation of barChartFacet feature in click display. diff --git src/hg/hgc/facetedBar.c src/hg/hgc/facetedBar.c new file mode 100644 index 0000000..0d7a876 --- /dev/null +++ src/hg/hgc/facetedBar.c @@ -0,0 +1,328 @@ +#include "common.h" +#include "hash.h" +#include "hdb.h" +#include "web.h" +#include "hvGfx.h" +#include "trashDir.h" +#include "hCommon.h" +#include "hui.h" +#include "asParse.h" +#include "hgc.h" +#include "trackHub.h" +#include "hgColors.h" +#include "fieldedTable.h" +#include "tablesTables.h" +#include "facetField.h" + +#include "barChartBed.h" +#include "barChartData.h" +#include "barChartSample.h" +#include "barChartUi.h" +#include "hgConfig.h" +#include "facetedBar.h" + + +struct facetedTable +/* Help manage a faceted table */ + { + struct facetedTable *next; + char *name; /* Name of file or database table */ + char *varPrefix; /* Prefix used on variables */ + }; + +struct facetedTable *facetedTableNew(char *name, char *varPrefix) +{ +struct facetedTable *ft; +AllocVar(ft); +ft->name = cloneString(name); +ft->varPrefix = cloneString(varPrefix); +return ft; +} + +void facetedTableFree(struct facetedTable **pFt) +/* Free up resources associated with faceted table */ +{ +struct facetedTable *ft = *pFt; +if (ft != NULL) + { + freeMem(ft->name); + freeMem(ft->varPrefix); + freez(pFt); + } +} + + +void facetedTableWebInit() +/* Print out scripts and css that we need. We should be in a page body or title. */ +{ +webIncludeResourceFile("facets.css"); +printf("\t\t"); +printf("\t\t\n" + "\n" + "\t\t\n" + "\t\t\n" + "\n" + "\t\t\n" + "\t\t\n" + ); +printf(""); +} + +char *facetedTableSelOp(struct facetedTable *ft, struct cart *cart) +/* Look up selOp in cart */ +{ +char var[256]; +safef(var, sizeof(var), "%s_facet_op", ft->varPrefix); +return cartOptionalString(cart, var); +} + +char *facetedTableSelField(struct facetedTable *ft, struct cart *cart) +/* Look up sel field in cart */ +{ +char var[256]; +safef(var, sizeof(var), "%s_facet_fieldName", ft->varPrefix); +return cartOptionalString(cart, var); +} + +char *facetedTableSelVal(struct facetedTable *ft, struct cart *cart) +/* Look up sel val in cart */ +{ +char var[256]; +safef(var, sizeof(var), "%s_facet_fieldVal", ft->varPrefix); +return cartOptionalString(cart, var); +} + +char *facetedTableSelList(struct facetedTable *ft, struct cart *cart) +/* Look up sel val in cart */ +{ +char var[256]; +safef(var, sizeof(var), "%s_facet_selList", ft->varPrefix); +return cartOptionalString(cart, var); +} + +void facetedTableRemoveOpVars(struct facetedTable *ft, struct cart *cart) +/* Remove sel op/field/name vars from cart */ +{ +char var[256]; +safef(var, sizeof(var), "%s_facet_op", ft->varPrefix); +cartRemove(cart, var); +safef(var, sizeof(var), "%s_facet_fieldVal", ft->varPrefix); +cartRemove(cart, var); +safef(var, sizeof(var), "%s_facet_fieldName", ft->varPrefix); +cartRemove(cart, var); +} + +boolean facetedTableUpdateOnFacetClick(struct facetedTable *ft, struct cart *cart) +/* If we got called by a click on a facet deal with that and return TRUE, else do + * nothing and return false */ +{ +char *selOp = facetedTableSelOp(ft, cart); +if (selOp) + { + char *selFieldName = facetedTableSelField(ft, cart); + char *selFieldVal = facetedTableSelVal(ft, cart); + if (selFieldName && selFieldVal) + { + 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 colorIx; /* Index of color in row */ + int valIx; /* Where value lives */ + double maxVal;/* Maximum of any total value */ + }; + +void wrapVal(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 x = sqlDouble(val); +int width = 500, height = 13; // These are units of ~2010 pixels or something +double barWidth = (double)width*x/wc->maxVal; +printf("", barWidth, height); +printf("", + barWidth, height, color); +printf(""); +printf(" %6.2f", x); +} + +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 */ + +struct fieldedTable *addChartVals(struct fieldedTable *table, struct barChartBed *chart) +/* All a new column with chart values */ +{ +if (chart->expCount != table->rowCount) + errAbort("Mismatch in field counts between %s (%d) and barChartBed (%d)", + table->name, table->rowCount, chart->expCount); +int oldFieldCount = table->fieldCount; +int newFieldCount = oldFieldCount+1; +char *newRow[newFieldCount]; +int i; +for (i=0; ifields[i]; +newRow[oldFieldCount] = "val"; +struct fieldedTable *newTable = fieldedTableNew(table->name, newRow, newFieldCount); +struct fieldedRow *fr; +int rowIx = 0; +for (fr = table->rowList; fr != NULL; fr = fr->next, ++rowIx) + { + for (i=0; irow[i]; + char buf[16]; + safef(buf, sizeof(buf), "%g", chart->expScores[rowIx]); + newRow[oldFieldCount] = lmCloneString(newTable->lm, buf); + fieldedTableAdd(newTable, newRow, newFieldCount, fr->id); + } +return newTable; +} + +void facetedBarChart(char *item, struct barChartBed *chart, struct trackDb *tdb, + double maxVal, char *statsFile, char *facets, char *metric) +{ +char *trackName = tdb->track; +struct sqlConnection *conn = sqlConnect(database); +struct hash *emptyHash = hashNew(0); +struct hash *wrapperHash = hashNew(0); +struct facetedTable *ft = facetedTableNew(tdb->shortLabel, trackName); + +/* Write out html to pull in the other files we use. */ +facetedTableWebInit(); + +/* Set up url that has enough context to get back to us. */ +struct dyString *returnUrl = dyStringNew(0); +dyStringPrintf(returnUrl, "../cgi-bin/hgc?g=%s", trackName); +if (item != NULL) + dyStringPrintf(returnUrl, "&i=%s", item); +dyStringPrintf(returnUrl, "&%s", cartSidUrlString(cart)); + +/* Working within a form we save context */ +printf("
\n"); +printf("
"); +cartSaveSession(cart); +cgiContinueHiddenVar("g"); +cgiContinueHiddenVar("i"); + +/* Put up the big faceted search table in a new div */ + +/* Load up table from tsv file */ +char *requiredStatsFields[] = {"count",}; +struct fieldedTable *statsTable = fieldedTableFromTabFile(statsFile, statsFile, + requiredStatsFields, ArraySize(requiredStatsFields)); +struct fieldedTable *table = addChartVals(statsTable, chart); + +/* Update facet selections from users input if any */ +facetedTableUpdateOnFacetClick(ft, cart); + +/* Do facet selection calculations */ +char *selList = facetedTableSelList(ft, cart); +struct facetField *ffArray[table->fieldCount]; +struct fieldedTable *selected = facetFieldsFromFieldedTable(table, selList, ffArray); + + + +/* Set up wrappers for some of output fields */ +struct wrapContext context = {.nameIx = 0, + .countIx = fieldedTableFindFieldIx(table, "count"), + .valIx = fieldedTableFindFieldIx(table, "val"), + .colorIx = fieldedTableFindFieldIx(table, "color"), + }; +context.maxVal = fieldedTableMaxInCol(table, context.valIx); + +/* Put up faceted search and table of visible fields. */ +char displayList[256]; +safef(displayList, sizeof(displayList), "%s,count,val", table->fields[0]); +hashAdd(wrapperHash, "val", wrapVal); +webFilteredFieldedTable(cart, selected, + displayList, returnUrl->string, trackName, + 32, wrapperHash, &context, + FALSE, NULL, + selected->rowCount, 7, + NULL, emptyHash, + ffArray, facets, + NULL); + +/* Clean up and go home. */ +printf("
\n"); +hashFree(&emptyHash); +sqlDisconnect(&conn); +} +