3522a9acc8256a35230b07f2e7ab3fc08c827f33 mspeir Sat Sep 5 17:19:20 2026 -0700 singleCellSignalsPeaks: correct the hg38 description page counts and cite BrainVar, refs #38219 From the v503 code review. Commit 3aac3982aa2 dropped 5 hg38 subtracks and updated the makeDoc, but the dataset list on the description page was missed, so the page disagreed with both the .ra and the facet menu: - Risk Loci in Alzheimer's and Parkinson's: 1 peak subtrack, not 2 (neuro-degen-atac/peaks.bb was the one dropped) - BrainVar: 9 signal subtracks, not 13, and the text still described tracks "for all nuclei together" -- the 4 combined-stage tracks are exactly the ones dropped, so every remaining BrainVar track carries a life stage Counts re-derived from the .ra by type (bigWig = signal, else peak): the other 7 hg38 datasets and all 9 mm10 datasets were already right, 929 and 587 total. BrainVar was also the only hg38 dataset with no citation, while its methods text had grown quite specific. It now cites Werling et al. 2020, which described the cohort, with the caveat that the single-nucleus data shown here were not part of that paper -- the same distinction the Cell Browser desc.conf makes. Citing it bare would credit a bulk RNA-seq and WGS study for 10x Multiome data. References are alphabetical, so hg38 is now 10 and mm10 still 7. copySingleCellSignalsPeaksFiles.py: colors_json() reads the palette in a with block, and a malformed R,G,B row now raises the SystemExit the rest of the file uses, naming the file, line number and offending field, instead of a bare ValueError or TypeError from int() or the %02X format. Output is unchanged. makeDoc: the mm10 cell-class note now records that the bare "Progenitor" row in celltype-class.tsv is live rather than leftover -- build_stanzas' class_key() collapses plurals, so BrainVar's "Progenitors" looks up under the singular key and takes its class and color from that one row. Retiring or qualifying the row would grey out that track. A non-neural label needs a specific cell type added instead, which is how "Nephron progenitors" comes out Stromal. Also fixed a contradiction there: the file claimed celltype-class.tsv is built by build_celltype_crosswalks.py a hundred lines above the note saying, correctly, that it is hand-curated and not generated. The submitters confirmed BrainVar is 100 bp tiles, so the 1 kb in their methods text is an error and the page is right; recorded in the hg38 makeDoc. Co-Authored-By: Claude Opus 5 (1M context) diff --git src/hg/makeDb/doc/mm10/singleCellSignalsPeaks.txt src/hg/makeDb/doc/mm10/singleCellSignalsPeaks.txt index 698deb5d354..0dfe2a09346 100644 --- src/hg/makeDb/doc/mm10/singleCellSignalsPeaks.txt +++ src/hg/makeDb/doc/mm10/singleCellSignalsPeaks.txt @@ -82,31 +82,32 @@ ############################################################################## # build_stanzas.py derives the display metadata rather than copying the source # hub's cryptic cluster labels. The same logic runs for hg38 (see # doc/hg38/singleCellSignalsPeaks.txt). # # Cell type: the source cluster label is cleaned and, for datasets with coded # cluster names, mapped to a canonical name via a paper-curated crosswalk # (celltype-crosswalks/.tsv; codes decoded from Li 2021 PMID 34616068, # Zhang 2022 PMID 36207411, Zhu 2021 PMID 33589836, and the Allen whole-brain # taxonomy). Redundant synonyms are merged, QC clusters (doublet / low-quality / # batch) are dropped, and commas become ';' (the faceted UI tokenizes cell # values on commas). The full cell type is a searchable table column (_Cell_type), # not a facet -- there are too many values. # # Cell class: each cell type is assigned one of 23 broad classes -# (celltype-crosswalks/celltype-class.tsv, built by build_celltype_crosswalks.py). +# (celltype-crosswalks/celltype-class.tsv, hand-curated -- NOT written by +# build_celltype_crosswalks.py; see the Cell classes note below). # The class drives BOTH the track color (one colorblind-conscious palette, # celltype-palette.tsv, shared by hg38 and mm10 so a class is the same color on # both assemblies) and the subtrack priority. Cell class is the primary cell facet, # and the same palette is published as the facet swatch colors (section 2). # # "Other glia" (88,160,88) was added because "Other" was doing four unrelated # jobs. Of 40 tracks corpus-wide sitting in it: 14 real glia with nowhere else to # go, 14 peripheral glia deliberately placed there (Schwann / enteric -- left # alone), 5 that are not cell types at all (All cell types / All cells / # Neuronal and glial -- aggregate peak calls, a separate defect NOT addressed), # and 6 genuinely other. The new class takes the glial aggregate labels (Glia, # Glial), olfactory ensheathing cells, and the five fly glia subtypes; Schwann and # enteric glia stay under "Other". Named for symmetry with the existing # "Other neuron". The color came from a grid search maximizing minimum dE against # the 22 existing entries under normal, deuteranope and protanope simulation, @@ -181,30 +182,42 @@ # Cell_class and color. The tables now normalize their keys on load (class_key, # _ct_lower_key, _ct_matchkey) so either spelling matches, and any cell type with no # broad class is reported in unclassified-celltypes.log plus counted in # facet-coverage.md rather than silently becoming "unknown". # # Cell classes: Nephron progenitor used to come out as class "Neural progenitor". The # decode tables carry a bare broad class of "Progenitor", and build_celltype_crosswalks # mapped that to "Neural progenitor" -- right for the radial glia and neuroblasts that # make up the rest of the class, wrong for kidney. Nephron progenitors are Six2+ cap # mesenchyme, so they are now classed Stromal (NON_NEURAL_PROGENITOR); the HTML legend # no longer lists them under Neural progenitor. Note celltype-class.tsv is hand-curated # (the union of the mm10 crosswalk classes with paper-decodes/hg38_ct_class.tsv), NOT # generated -- build_celltype_crosswalks.py does not write it, so a class change has to # be made there too. # +# The bare "Progenitor" row in celltype-class.tsv is live, not leftover -- do not +# retire it. build_stanzas' class_key() collapses plurals, so BrainVar's cell type +# "Progenitors" (hg38, prenatal only) looks up under the singular key and gets its +# Neural progenitor class and indigo color from that one row. Nothing in the row says +# so, and no track's label matches it literally, so it reads as dead. +# It is also genuinely ambiguous: a bare "Progenitor" is not evidence of a neural +# lineage, and the corpus now spans kidney, heart and blood. Remapping the row is the +# wrong fix (it would grey out BrainVar's progenitor track). When a non-neural dataset +# arrives with such a label, add the specific cell type instead -- a specific entry +# beats its own prefix in lookup_class(), which is how "Nephron progenitors" comes out +# Stromal while the bare row stays neural. +# # One copy of the crosswalks: build_stanzas reads celltype-crosswalks/ out of the kent # tree (XWALK_ROOT, overridable), not the copy in the hub-build dir. There used to be # two independent copies and they drifted -- a stale local copy silently reverted the # cell-class fix above while the kent copy looked correct. # # The curation of record is archived with the scripts: # scripts/singleCellSignalsPeaks/build_celltype_crosswalks.py # scripts/singleCellSignalsPeaks/celltype-crosswalks/ (per-collection crosswalks, # celltype-palette.tsv, celltype-class.tsv, sea-ad-celltype-crosswalk.tsv) # scripts/singleCellSignalsPeaks/celltype-crosswalks/paper-decodes/ (the paper-curated # decode tables, each row's `note` giving its source justification) # build_celltype_crosswalks.py rebuilds the crosswalks + palette from paper-decodes/. # The general hub machinery that consumes them (build_manifest.py, build_stanzas.py, # build_hub.py, hub_config.json) lives in the cellBrowser repo, not in the kent tree -- # it builds the whole super hub, not just this track: