55858fedabd0a942ed8639db3ea0fd5fcfd3104b chmalee Thu Feb 26 15:00:25 2026 -0800 Make hubApi wig table output behave like a bedgraph instead of having a top level key with the chromosome name that contains all the data, now there is a key with the trackName and then bedgraph like data of chrom,start,stop,value. Does not affect bigBed output which already worked this way. Clean up some missing 'let' declarations and fix some for loop logic in the download data in window feature, refs #36802,#36858 diff --git src/hg/hubApi/getData.c src/hg/hubApi/getData.c index 89c2f62c026..896e3b7949b 100644 --- src/hg/hubApi/getData.c +++ src/hg/hubApi/getData.c @@ -16,38 +16,40 @@ unsigned itemCount = 0; for (el = wds->ascii; (itemCount + itemsDone) < maxItemsOutput && el; el = el->next) { unsigned span = el->span; unsigned count = el->count; unsigned i = 0; struct asciiDatum *data = el->data; for ( ; (i < count) && ((itemCount + itemsDone) < maxItemsOutput); i++,data++) { int s = data->chromStart; int e = s + span; double val = data->value; if (jsonOutputArrays) { jsonWriteListStart(jw, NULL); + jsonWriteString(jw, NULL, chrom); jsonWriteNumber(jw, NULL, (long long)s); jsonWriteNumber(jw, NULL, (long long)e); jsonWriteDouble(jw, NULL, val); jsonWriteListEnd(jw); } else { jsonWriteObjectStart(jw, NULL); + jsonWriteString(jw, "chrom", chrom); jsonWriteNumber(jw, "start", (long long)s); jsonWriteNumber(jw, "end", (long long)e); jsonWriteDouble(jw, "value", val); jsonWriteObjectEnd(jw); } ++itemCount; } } if ((itemCount + itemsDone) >= maxItemsOutput) reachedMaxItems = TRUE; return itemCount; } /* static unsigned wigTableDataOutput(struct jsonWrite *jw, ...) */ static void jsonDatumOut(struct jsonWrite *jw, char *name, char *val, int jsonType) @@ -193,54 +195,54 @@ sqlDyStringPrintf(query, "select * from %s", splitSqlTable); } else if (0 == (start + end)) /* have chrom, no start,end == full chr */ { if (! sqlColumnExists(conn, splitSqlTable, chromName)) apiErrAbort(err400, err400Msg, "track '%s' is not a position track, request track without chrom specification, genome: '%s'", track, db); jsonWriteString(jw, "chrom", chrom); struct chromInfo *ci = hGetChromInfo(db, chrom); jsonWriteNumber(jw, "start", (long long)0); jsonWriteNumber(jw, "end", (long long)ci->size); if (tdb && isWiggleDataTable(tdb->type)) { if (jsonOutputArrays || debug) wigColumnTypes(columnTypesJw, track); - jsonWriteListStart(jw, chrom); + jsonWriteListStart(jw, track); itemsReturned += wigTableDataOutput(jw, db, splitSqlTable, chrom, 0, ci->size, 0); jsonWriteListEnd(jw); return; /* DONE */ } else { if (sqlColumnExists(conn, splitSqlTable, startName)) sqlDyStringPrintf(query, "select * from %s where %s='%s' order by %s", splitSqlTable, chromName, chrom, startName); else sqlDyStringPrintf(query, "select * from %s where %s='%s'", splitSqlTable, chromName, chrom); } } else /* fully specified chrom:start-end */ { if (! sqlColumnExists(conn, splitSqlTable, chromName)) apiErrAbort(err400, err400Msg, "track '%s' is not a position track, request track without chrom and start,end specifications, genome: '%s'", track, db); jsonWriteString(jw, "chrom", chrom); if (tdb && isWiggleDataTable(tdb->type)) { if (jsonOutputArrays || debug) wigColumnTypes(columnTypesJw, track); - jsonWriteListStart(jw, chrom); + jsonWriteListStart(jw, track); itemsReturned += wigTableDataOutput(jw, db, splitSqlTable, chrom, start, end, 0); jsonWriteListEnd(jw); return; /* DONE */ } else { sqlDyStringPrintf(query, "select * from %s where ", splitSqlTable); if (sqlColumnExists(conn, splitSqlTable, startName)) { if (hti->hasBin) hAddBinToQuery(start, end, query); sqlDyStringPrintf(query, "%s='%s' AND %s > %u AND %s < %u ORDER BY %s", chromName, chrom, endName, start, startName, end, startName); } else apiErrAbort(err400, err400Msg, "track '%s' is not a position track, request track without start,end specification, genome: '%s'", track, db); @@ -277,32 +279,32 @@ slSort(ciList, chromInfoCmp); struct chromInfo *ci = ciList; for ( ; ci && itemsDone < maxItemsOutput; ci = ci->next ) { jsonWriteListStart(jw, ci->chrom); /* starting a chrom output */ dyStringFree(&query); query = dyStringNew(64); if (hti && hti->isSplit) /* when split, make up split chr name */ { safef(fullTableName, sizeof(fullTableName), "%s_%s", ci->chrom, hti->rootName); sqlDyStringPrintf(query, "select * from %s where %s='%s'", fullTableName, chromName, ci->chrom); } else sqlDyStringPrintf(query, "select * from %s where %s='%s'", splitSqlTable, chromName, ci->chrom); if (tdb && isWiggleDataTable(tdb->type)) - itemsDone += wigTableDataOutput(jw, db, splitSqlTable, chrom, - start, end, itemsDone); + itemsDone += wigTableDataOutput(jw, db, splitSqlTable, ci->chrom, + 0, ci->size, itemsDone); else itemsDone += sqlQueryJsonOutput(conn, jw, query->string, columnCount, columnNames, jsonTypes, itemsDone); jsonWriteListEnd(jw); /* chrom data output list end */ } if (itemsDone >= maxItemsOutput) reachedMaxItems = TRUE; jsonWriteObjectEnd(jw); /* end track data output */ itemsReturned += itemsDone; } else { /* a single chrom has been requested, run it */ jsonWriteListStart(jw, track); /* data output list starting */ itemsDone += sqlQueryJsonOutput(conn, jw, query->string, columnCount, columnNames, jsonTypes, itemsDone); @@ -373,55 +375,55 @@ reachedMaxItems = TRUE; lmCleanup(&bbLm); return itemCount; } /* static void bbiDataOutput(struct jsonWrite *jw, . . . ) */ static unsigned wigDataOutput(struct jsonWrite *jw, struct bbiFile *bwf, char *chrom, unsigned start, unsigned end) /* output wig data for one chrom in the given bwf file, return itemCount out */ { unsigned itemCount = 0; struct lm *lm = lmInit(0); struct bbiInterval *iv, *ivList = bigWigIntervalQuery(bwf, chrom, start, end, lm); if (NULL == ivList) return itemCount; -jsonWriteListStart(jw, chrom); for (iv = ivList; iv && itemCount < maxItemsOutput; iv = iv->next) { int s = max(iv->start, start); int e = min(iv->end, end); double val = iv->val; if (jsonOutputArrays) { jsonWriteListStart(jw, NULL); + jsonWriteString(jw, NULL, chrom); jsonWriteNumber(jw, NULL, (long long)s); jsonWriteNumber(jw, NULL, (long long)e); jsonWriteDouble(jw, NULL, val); jsonWriteListEnd(jw); } else { jsonWriteObjectStart(jw, NULL); + jsonWriteString(jw, "chrom", chrom); jsonWriteNumber(jw, "start", (long long)s); jsonWriteNumber(jw, "end", (long long)e); jsonWriteDouble(jw, "value", val); jsonWriteObjectEnd(jw); } ++itemCount; } -jsonWriteListEnd(jw); if (itemCount >= maxItemsOutput) reachedMaxItems = TRUE; return itemCount; } /* static unsigned wigDataOutput(...) */ static void bigWigData(struct jsonWrite *jw, struct bbiFile *bwf, char *chrom, unsigned start, unsigned end) /* output the data for a bigWig bbi file */ { struct bbiChromInfo *chromList = NULL; unsigned itemsDone = 0; if (isEmpty(chrom)) { chromList = bbiChromList(bwf); struct bbiChromInfo *bci; @@ -545,33 +547,33 @@ fiList, thisTrack, itemsDone); } if (itemsDone >= maxItemsOutput) reachedMaxItems = TRUE; } else itemsDone += bbiDataOutput(jw, bbi, chrom, uStart, uEnd, fiList, thisTrack, itemsDone); itemsReturned += itemsDone; jsonWriteListEnd(jw); } else if (startsWith("bigWig", thisTrack->type)) { if (jsonOutputArrays || debug) wigColumnTypes(columnTypesJw, track); - jsonWriteObjectStart(jw, track); + jsonWriteListStart(jw, track); bigWigData(jw, bbi, chrom, uStart, uEnd); - jsonWriteObjectEnd(jw); + jsonWriteListEnd(jw); } bbiFileClose(&bbi); } if (jsonOutputArrays || debug) { jsonWriteObjectEnd(columnTypesJw); jsonWriteAppend(jw, NULL, columnTypesJw); jsonWriteFree(&columnTypesJw); } apiFinishOutput(0, NULL, jw); } /* static void getHubTrackData(char *hubUrl) */ static void getTrackData() /* return data from a track, optionally just one chrom data, * optionally just one section of that chrom data @@ -789,33 +791,33 @@ } if (itemsDone >= maxItemsOutput) reachedMaxItems = TRUE; } else itemsDone += bbiDataOutput(jw, bbi, chrom, uStart, uEnd, fiList, thisTrack, itemsDone); itemsReturned += itemsDone; jsonWriteListEnd(jw); } else if (thisTrack && startsWith("bigWig", thisTrack->type)) { if (jsonOutputArrays || debug) wigColumnTypes(columnTypesJw, track); - jsonWriteObjectStart(jw, track); + jsonWriteListStart(jw, track); bigWigData(jw, bbi, chrom, uStart, uEnd); - jsonWriteObjectEnd(jw); + jsonWriteListEnd(jw); bbiFileClose(&bbi); } else tableDataOutput(db, thisTrack, conn, jw, track, chrom, uStart, uEnd, columnTypesJw); } if (jsonOutputArrays || debug) { jsonWriteObjectEnd(columnTypesJw); jsonWriteAppend(jw, NULL, columnTypesJw); jsonWriteFree(&columnTypesJw); } apiFinishOutput(0, NULL, jw); hFreeConn(&conn); } /* static void getTrackData() */