ddb85ced5e8b6127a233b5cda5fcb1fbe2260578
max
  Wed Mar 25 04:22:06 2026 -0700
Add detailsScript trackDb mechanism for JS visualizations on bigBed details pages

Changing based on feedback from Jonathan, Chris and Brian after group
discussion. Refactored existing Claude-generated code, moving functions
into libraries.

This is the first use of ES6 modules in the kent js code. In 2026, this
should be acceptable?

New trackDb syntax: detailsScript.<plotType>.<fieldName> <jsonConfig>
The C code (bigBedClick.c) collects these settings, exports field values as JSON
(bedDetails object), and dynamically imports hgc.<plotType>.js as an ES6 module.
Fields used by detailsScript are shown in the HTML table with empty values,
filled by JavaScript.

Includes hgc.histogram.js module for drawing SVG bar chart histograms from
logfmt-encoded data (space-separated key=value pairs). Applied to both the
trexplorer and webstr tracks in the strVar supertrack.

Also adds jsonWriteJsonElement() helper to jsonWrite.c for writing parsed
jsonElement trees into a jsonWrite stream.

max, refs #36652
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

diff --git src/hg/makeDb/scripts/webstr/webstrToBed.py src/hg/makeDb/scripts/webstr/webstrToBed.py
index 1562887b37b..3e8068fc0ec 100644
--- src/hg/makeDb/scripts/webstr/webstrToBed.py
+++ src/hg/makeDb/scripts/webstr/webstrToBed.py
@@ -90,37 +90,36 @@
             fields = [
                 chrom,
                 start,
                 end,
                 truncateMotif(motif) + "x" + numcopies,  # name
                 "0",            # score
                 ".",            # strand
                 start,          # thickStart
                 end,            # thickEnd
                 color,          # itemRgb
                 motif,
                 period,
                 numcopies,
             ]
 
-            # Allele frequency fields for each cohort
+            # Allele frequency fields for each cohort (logfmt: allele=freq pairs)
             af = afreqs.get(repeatid)
             for cohort in COHORT_ORDER:
                 if af and af[cohort]["alleles"]:
                     entry = af[cohort]
-                    fields.append(",".join(entry["alleles"]))
-                    fields.append(",".join(entry["freqs"]))
+                    pairs = [a + "=" + f for a, f in zip(entry["alleles"], entry["freqs"])]
+                    fields.append(" ".join(pairs))
                     fields.append(str(entry["n"]))
                 else:
-                    fields.append("")
                     fields.append("")
                     fields.append("0")
 
             print("\t".join(fields))
             count += 1
             if count % 500000 == 0:
                 print(f"  Processed {count} repeats...", file=sys.stderr)
 
     print(f"Done. Wrote {count} records.", file=sys.stderr)
 
 if __name__ == "__main__":
     main()