32048e16a50722894cf28d9b7b4b050302e38c75
markd
  Wed Sep 30 17:54:58 2026 -0700
Spell the acronym PCLAI, not pcLAI. refs #35415

The authors write it PCLAI throughout: the upstream README at
AI-sandbox/hprc-pclai uses PCLAI 18 times and pcLAI never, under the title
"Point Cloud Local Ancestry Inference (PCLAI)". We had pcLAI in 517 places,
across the track labels, both description pages, the makedocs, the build scripts
and the autoSql.

hprcPclai.ra holds 467 of those, in shortLabel, longLabel, dataVersion and
comments. It is generated, so the fix went into hprcPclaiMakeTrackDb.py and the
file was rebuilt; every line of the resulting diff differs only by the rename.

Track names, file names and the lowercase pclai in URLs and data file names are
untouched. None of them contained the string pcLAI, and renaming the tracks would
break saved sessions for no user-visible gain.

diff --git src/hg/makeDb/scripts/hprc2annot/hprc2annotMakePclaiRefPanel.py src/hg/makeDb/scripts/hprc2annot/hprc2annotMakePclaiRefPanel.py
index 5ce31ec5c2c..11a29bac2af 100755
--- src/hg/makeDb/scripts/hprc2annot/hprc2annotMakePclaiRefPanel.py
+++ src/hg/makeDb/scripts/hprc2annot/hprc2annotMakePclaiRefPanel.py
@@ -1,81 +1,81 @@
 #!/usr/bin/env python3
-"""Build the pcLAI reference-panel scatterplot data file for the hprc2annot hub.
+"""Build the PCLAI reference-panel scatterplot data file for the hprc2annot hub.
 
-The pcLAI authors publish the PCA coordinates of the 1000 Genomes reference
-haplotypes that define the ancestry space each pcLAI window is placed in:
+The PCLAI authors publish the PCA coordinates of the 1000 Genomes reference
+haplotypes that define the ancestry space each PCLAI window is placed in:
 
   https://github.com/AI-sandbox/hprc-pclai/blob/main/reference_pca_metadata.tsv
 
 That table is turned into the compact JSON the hgc.scatterPlot.js module reads,
 which the pclai track points at with its detailsScript.scatterPlot setting.
 
 Population names are held in a separate list and referenced by index, because the
 descriptors are long and repeat across thousands of haplotypes; each point also
 carries its own haplotype id, which hgc.scatterPlot.js shows on mouseover.
 
   hprc2annotMakePclaiRefPanel.py <reference_pca_metadata.tsv> <out.json>
 """
 import sys
 import csv
 import json
 
 # The published TSV has one mis-decoded en dash (U+00D0 where an en dash belongs),
 # which would otherwise show up in the plot legend.
 FIXUPS = {"Ð": "-"}
 
 
 def clean(s):
     for bad, good in FIXUPS.items():
         s = s.replace(bad, good)
     # collapse the whitespace a fixup can leave behind
     return " ".join(s.split())
 
 
 def main():
     if len(sys.argv) != 3:
         sys.exit(__doc__)
     inFname, outFname = sys.argv[1], sys.argv[2]
 
     labels = []
     labelIdx = {}
     points = []
     with open(inFname, encoding="utf-8") as fh:
         for row in csv.DictReader(fh, delimiter="\t"):
             try:
                 x = float(row["x1"])
                 y = float(row["x2"])
             except (TypeError, ValueError):
                 continue
             pop = clean(row.get("Population_descriptor") or "")
             if pop not in labelIdx:
                 labelIdx[pop] = len(labels)
                 labels.append(pop)
             hap = clean(row.get("Sample_hap") or row.get("Sample") or "")
             # 3 decimals is finer than one screen pixel over this ~2.6 unit range
             points.append([round(x, 3), round(y, 3), labelIdx[pop], hap])
 
     if not points:
         sys.exit("no usable rows in %s" % inFname)
 
     # Order labels by their cluster's PC1 then PC2, so the legend reads in the same
     # left-to-right order as the clusters appear in the plot.
     sums = {}
     for x, y, li, _hap in points:
         sx, sy, n = sums.get(li, (0.0, 0.0, 0))
         sums[li] = (sx + x, sy + y, n + 1)
     order = sorted(range(len(labels)),
                    key=lambda li: (sums[li][0] / sums[li][2], sums[li][1] / sums[li][2]))
     remap = {old: new for new, old in enumerate(order)}
     labels = [labels[old] for old in order]
     points = [[x, y, remap[li], hap] for x, y, li, hap in points]
 
     with open(outFname, "w", encoding="utf-8") as out:
         json.dump({"labels": labels, "points": points}, out, separators=(",", ":"))
         out.write("\n")
 
     sys.stderr.write("%s: %d points, %d populations\n"
                      % (outFname, len(points), len(labels)))
 
 
 if __name__ == "__main__":
     main()