d87ef2fb8472135b899fd1a89434033d5895217a
mspeir
  Thu Oct 1 15:31:26 2026 -0700
Add barChartReorder, a utility for changing the order of the bars in a barChart track, refs #37619

The bars of a barChart are drawn in the order their values appear in the
expScores field, and nothing re-sorts them when the track is drawn, so the
order is a property of the data file. Putting the bars in a different order
means rewriting that field in every row, which is awkward enough by hand that
we have twice done it for a data author instead of explaining it. This has
come up on #36998 and #37001.

barChartReorder takes the current bar order and the wanted order as two lists
of names, rewrites expScores in every row, optionally puts a .categories file
into the same order, and prints the barChartBars line for the track. It works
on any barChart BED whatever produced it, so unlike the --groupOrderFile
option of expMatrixToBarchartBed it does not assume the file was built here
from an expression matrix. A bigBarChart is handled by converting it with
bigBedToBed and rebuilding it afterwards, which the usage message spells out.

It refuses to write a half-correct file: the two orders must name the same
bars, every row must hold as many values as there are names, and a .categories
file must have a row for each bar.

Listed in USER_APP_SCRIPTS so it reaches hgdownload, and in the no-argument
branch of mkREADME.sh so the README picks up its usage message rather than the
argparse error that -verbose=2 would produce.

Its tests are also wired into the test target directly. testAll iterates
ALL_APPS, which does not include USER_APP_SCRIPTS, so none of these programs'
tests have ever been reachable from "make test" - that is why the suite sitting
next to expMatrixToBarchartBed never reported it was broken. The makefile
already keeps a short list of directories testAll cannot reach, and this adds
two more to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git src/utils/makefile src/utils/makefile
index d9e29c8a34a..495d6e7cf96 100644
--- src/utils/makefile
+++ src/utils/makefile
@@ -160,30 +160,31 @@
 	textHist2 \
 	udcCleanup \
 	undupFa \
 	upper \
 	vcfFilter \
 	venn \
 	verticalSplitSqlTable \
 	weedLines
 
 # These are parts of the user apps build, so they will land on hgdownload
 # These are not C programs, so no clean up
 
 USER_APP_SCRIPTS = \
 	bedJoinTabOffset.py \
 	expMatrixToBarchartBed \
+	barChartReorder \
 	barChartMaxLimit \
 	ucscApiClient \
 	tdbRename \
 	tdbSort \
 	webSync \
 	chromToUcsc \
 	bigHeat \
 	bigGuessDb \
 	hubtools
 
 # Scripts that are not distributed outside of UCSC
 # They are not part of the user-apps build
 SCRIPT_FILES = \
 	agpToLift \
 	apacheLogParse \
@@ -278,30 +279,33 @@
 
 testAll: $(ALL_APPS:%=%.testAll)
 
 %.testAll:
 	@test -s $*/tests/makefile && (echo $*; cd $* && $(MAKE) test) || true
 
 test: testAll
 	cd faToTwoBit && ${MAKE} test
 	cd twoBitToFa && ${MAKE} test
 	cd twoBitInfo && ${MAKE} test
 	cd bedGeneParts && ${MAKE} test
 # testRegistry is not an app, so the testAll rule above cannot reach it.  Its test checks
 # that every row of the ticket-to-test registry still names a test that is in the tree,
 # refs #38391.
 	cd testRegistry && ${MAKE} test
+# USER_APP_SCRIPTS are not in ALL_APPS either, so testAll cannot reach their tests.
+	cd barChartReorder && ${MAKE} test
+	cd expMatrixToBarchartBed && ${MAKE} test
 
 clean: $(ALL_APPS:%=%.clean)
 	touch non-empty-rm.o
 	- find . -name \*.o -print | xargs rm
 
 %.clean:
 	cd $* && echo $* && $(MAKE) clean
 
 BAD_DIRS= \
 	ccCpLock \
 	est2genomeToPsl \
 	geneStarts \
 	jimgrep \
 	jkShell \
 	wigAsciiToBinary \