2904215904f1e62317b16bb372a6b176c1f800bd
braney
Sat Jul 25 09:58:54 2026 -0700
add an inventory of track-scoped cart variables refs #37838
Before changing the cart format we need to know what is actually stored in it.
cartTrackVarCatalog.py holds a curated catalog of the 340 track-scoped cart
variables in the tree, arranged as the hierarchy a JSON cart would use: track
name, then the variables common to any track, then a layer per track type, then
the leaf groups shared across types. It emits either JSON or a browsable HTML
page, and --check verifies that every leaf group a type refers to exists.
harvestCartVars.py is the scanner that seeds it. It finds the two ways a
track-scoped name gets built, cart*ClosestToHome() and safef("%s.%s"), resolves
macro identifiers to their string values, and attributes each hit to the
function that reads or writes it. Its output still needs curation by hand, since
it cannot tell a cart variable from a table name or a filename suffix.
No makefile: this is a documentation generator, so it is left out of the utils
DIRS list, same as hg/utils/otto.
diff --git src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py
new file mode 100755
index 00000000000..a258c7a4fa0
--- /dev/null
+++ src/hg/utils/cartTrackVarCatalog/cartTrackVarCatalog.py
@@ -0,0 +1,1702 @@
+#!/usr/bin/env python3
+"""cartTrackVarCatalog.py - the registry of track-scoped cart variables.
+
+Refs #37838. This is the hand-curated catalog that backs two things:
+
+ 1. The JSON cart schema (#37838) - the hierarchy below is the shape the
+ stored cart wants to grow into: track name at the top, then the vars
+ every track has, then a per-type section, then nested leaf groups.
+ 2. The planned cart accessor layer - each entry names one variable, its
+ value type, its separator, and where the tree reads it, so accessors
+ can be generated or at least checked against reality.
+
+Harvested mechanically from cart*ClosestToHome() and safef("%s.%s") call
+sites in hg/lib, hg/hgTracks, hg/hgTrackUi and hg/cgilib, then curated by
+hand: names that turned out to be table names, file suffixes or non-cart
+strings were dropped, macro identifiers were resolved to their values, and
+the type/enum/default columns were read out of the UI code.
+
+Usage:
+ cartTrackVarCatalog.py --json out.json
+ cartTrackVarCatalog.py --html out.html
+ cartTrackVarCatalog.py --check # sanity checks, prints counts
+"""
+
+import argparse
+import html
+import json
+import re
+import sys
+
+# ---------------------------------------------------------------------------
+# how a track-scoped name is built
+# ---------------------------------------------------------------------------
+
+NAMING = {
+ "canonical": "<track>.<var>",
+ "legacy": "<track>_<var>",
+ "legacyNote":
+ "The underscore form predates the dot form. cartRemoveAllForTdb() "
+ "(hg/lib/cart.c:3306) removes both prefixes plus the bare track name, "
+ "and carries the comment 'All should be {track}.{varName}'. Any "
+ "rewrite should keep reading both.",
+ "lookupOrder": [
+ "<subtrack>.<var>",
+ "<composite>.<view>.<var>",
+ "<composite>.<var>",
+ ],
+ "lookupOrderSrc": "hg/lib/cart.c:cartLookUpVariableClosestToHome",
+ "lookupOrderNote":
+ "parentLevel=TRUE starts the search at the parent, so a subtrack "
+ "setting always wins over its view, which wins over its composite. "
+ "The JSON form needs to preserve that three-level fallback, not "
+ "flatten it.",
+ "trackNamePrefixes": [
+ {"prefix": "hub_<hubId>_", "what": "track hub track",
+ "src": "hg/lib/trackHub.c"},
+ {"prefix": "ct_", "what": "custom track",
+ "src": "hg/lib/customTrack.c"},
+ {"prefix": "dup_<n>_", "what": "duplicated track",
+ "src": "hg/inc/dupTrack.h:DUP_TRACK_PREFIX"},
+ ],
+ "valueEncoding":
+ "Everything is a string in the cart hash. The 'type' column below is "
+ "how the reader interprets it, and is what the JSON form could encode "
+ "natively. 'list' vars are multi-valued: the same name appears more "
+ "than once in the var=val encoding and must become a JSON array.",
+}
+
+# ---------------------------------------------------------------------------
+# helpers
+# ---------------------------------------------------------------------------
+
+def v(name, type_, src, sep=".", values=None, default=None, note=None,
+ tdb=None, multi=False):
+ """One catalog entry.
+
+ name variable name after the <track> prefix and separator
+ type_ bool | int | float | string | enum | list | color | hidden
+ src file:line where the tree reads or writes it
+ sep '.' (canonical) or '_' (legacy)
+ values allowed values for enums
+ tdb trackDb setting that supplies the default, if differently named
+ """
+ d = {"name": name, "type": type_, "sep": sep, "src": src}
+ if values:
+ d["values"] = values
+ if default is not None:
+ d["default"] = default
+ if tdb:
+ d["tdbDefault"] = tdb
+ if multi:
+ d["multi"] = True
+ if note:
+ d["note"] = note
+ return d
+
+
+# ---------------------------------------------------------------------------
+# LEVEL 2: variables every track can have, whatever its type
+# ---------------------------------------------------------------------------
+
+COMMON = {
+ "visibility": {
+ "what": "What the track is set to. The only var that is the bare "
+ "track name with no suffix at all.",
+ "vars": [
+ v("", "enum", "hg/lib/hui.c:9954", sep="",
+ values=["hide", "dense", "squish", "pack", "full"],
+ note="Bare <track>. For a superTrack the values are "
+ "'show'/'hide' instead (hg/lib/hui.c:9887). This is the "
+ "var #37838 discussed moving under a 'vis.' prefix."),
+ v("_sel", "bool", "hg/lib/hui.c:5434", sep="_",
+ note="Subtrack/composite-member checkbox. Four-state in the "
+ "UI (checked, unchecked, checked-disabled) but stored 0/1; "
+ "see fourState* in hg/inc/hui.h."),
+ v("_hideKids", "bool", "hg/hgTracks/hgTracks.c:7652", sep="_",
+ note="Container collapsed in hgTracks, children not drawn."),
+ v("_faux", "hidden", "hg/lib/hui.c:5524", sep="_",
+ note="UI-only element id, not persisted state."),
+ v("_toggle", "hidden", "hg/lib/hui.c:5529", sep="_",
+ note="UI-only element id, not persisted state."),
+ ],
+ },
+ "layout": {
+ "what": "Where the track sits in the image and how tall it is.",
+ "vars": [
+ v("priority", "float", "hg/lib/hui.c:tdbAddPrioritiesFromCart",
+ tdb="priority",
+ note="User drag-reorder override of the trackDb priority."),
+ v("group", "string", "hg/hgTracks/hgTracks.c:groupTracks",
+ note="User moved the track into a different track group."),
+ v("_imgOrd", "int", "hg/hgTracks/imageV2.c:flatTracksSort", sep="_",
+ note="Row order in the image, set by drag-reorder in "
+ "hgTracks.js. Distinct from priority."),
+ v("heightPer", "int", "hg/inc/wiggle.h:HEIGHTPER",
+ default="128", tdb="maxHeightPixels",
+ note="Track height in pixels. Shared by wig, lolly, interact, "
+ "long, sample and vcf haplotype displays."),
+ ],
+ },
+ "color": {
+ "what": "Per-track color override, offered for any track whose type "
+ "supports it (tdbSupportsColorOverride).",
+ "vars": [
+ v("colorOverride", "color", "hg/lib/hui.c:colorTrackOption",
+ note="RGB as '#rrggbb'."),
+ v("colorOverrideOn", "bool", "hg/lib/hui.c:colorTrackOption"),
+ ],
+ },
+ "ui": {
+ "what": "State of the hgTrackUi page itself, not of the drawing.",
+ "vars": [
+ v("section_<section>_close", "bool",
+ "hg/lib/jsHelper.c:411",
+ note="One per collapsible section on the track's config page "
+ "(jsBeginCollapsibleSection). Known sections include "
+ "colorByAttribute, superDescription, superMembers."),
+ v("_button", "hidden", "hg/hgTracks/config.c:321", sep="_"),
+ v("_defaultBut", "hidden", "hg/hgTracks/config.c:348", sep="_"),
+ v("_hideAllBut", "hidden", "hg/hgTracks/config.c:331", sep="_"),
+ v("_showAllBut", "hidden", "hg/hgTracks/config.c:342", sep="_"),
+ v("_edit", "hidden", "hg/hgTracks/hgTracks.c:10121", sep="_"),
+ ],
+ },
+ "dataFilters": {
+ "what": "Filters offered for many types, not tied to one of them.",
+ "vars": [
+ v("nameFilter", "string", "hg/lib/hui.c:filterNameOption",
+ note="Wildcard match on item name."),
+ v("doMergeItems", "bool", "hg/inc/hui.h:MERGESPAN_CART_SETTING",
+ tdb="mergeSpannedItems",
+ note="Collapse items that span the whole window into one."),
+ v("doWiggle", "bool", "hg/lib/hui.c:wigOption",
+ note="Draw a bed/genePred/psl/bam type as a coverage wiggle. "
+ "When on, the whole wig type group below applies too."),
+ v("squishyPackPoint", "float", "hg/lib/hui.c:squishyPackOption",
+ note="Row count past which pack degrades to squish."),
+ v("doSnake", "bool", "hg/lib/hui.c:snakeOption",
+ note="Draw a chain/psl as a snake."),
+ ],
+ },
+}
+
+# ---------------------------------------------------------------------------
+# LEVEL 2b: containers - composite, view, superTrack, multiWig, faceted
+# ---------------------------------------------------------------------------
+
+CONTAINER = {
+ "composite": {
+ "what": "Vars a composite parent owns. Subtrack selection lives on "
+ "the child (<subtrack>_sel), not here.",
+ "vars": [
+ v("displaySubtracks", "enum", "hg/lib/hui.c:compositeUiSubtracks",
+ values=["all", "selected"]),
+ v("hideEmptySubtracks", "bool",
+ "hg/lib/hui.c:compositeHideEmptySubtracks",
+ tdb="hideEmptySubtracks"),
+ v("sortOrder", "string", "hg/lib/hui.c:sortOrderGet",
+ note="Subtrack table sort, e.g. 'cellType=+ view=-'."),
+ v("filterComp.<groupTag>", "list", "hg/lib/hui.c:3119", multi=True,
+ note="One per ABC dimension of a filterComposite. 'All' means "
+ "every option selected."),
+ v("subGroup<n>", "string", "hg/lib/hui.c:2905",
+ note="trackDb-side dimension definition, read back when "
+ "rebuilding the matrix."),
+ ],
+ },
+ "view": {
+ "what": "A composite view is a middle namespace, not a var of its "
+ "own: any type-layer var can appear as "
+ "<composite>.<view>.<var>.",
+ "vars": [
+ v("<view>.<anyTypeVar>", "varies",
+ "hg/lib/cart.c:cartLookUpVariableClosestToHome",
+ note="Middle level of the three-level lookup."),
+ v("_link", "hidden", "hg/lib/hui.c:hCompositeDisplayViewDropDowns",
+ sep="_"),
+ ],
+ },
+ "superTrack": {
+ "what": "SuperTracks have no drawing settings of their own.",
+ "vars": [
+ v("", "enum", "hg/lib/hui.c:9887", sep="",
+ values=["show", "hide"]),
+ v("_check", "hidden", "hg/hgTrackUi/hgTrackUi.c:2861", sep="_"),
+ v("_link", "hidden", "hg/hgTrackUi/hgTrackUi.c:2894", sep="_"),
+ ],
+ },
+ "multiWig": {
+ "what": "Overlay container. Uses the wig type group plus these.",
+ "vars": [
+ v("aggregate", "enum", "hg/inc/wiggle.h:AGGREGATE",
+ values=["none", "transparentOverlay", "solidOverlay",
+ "stacked", "add", "subtract"]),
+ v("viewFunc", "enum", "hg/inc/wiggle.h:VIEWFUNC",
+ values=["showAll", "addAll", "subtractAll"]),
+ v("showSubtrackColorOnUi", "bool",
+ "hg/inc/hui.h:SUBTRACK_COLOR_PATCH"),
+ ],
+ },
+ "facetedComposite": {
+ "what": "compositeTrack faceted. Facet state is keyed off a var "
+ "prefix, not the track name; see the exceptions section.",
+ "vars": [
+ v("_facet_selList", "string", "hg/lib/facetedTable.c:87", sep="_"),
+ v("_facet_fieldName", "string", "hg/lib/facetedTable.c:103",
+ sep="_"),
+ v("_facet_fieldVal", "string", "hg/lib/facetedTable.c:111",
+ sep="_"),
+ v("_facet_op", "string", "hg/lib/facetedTable.c:119", sep="_"),
+ ],
+ },
+}
+
+# ---------------------------------------------------------------------------
+# LEVEL 4: reusable leaf groups. Types below reference these by key.
+# ---------------------------------------------------------------------------
+
+FAMILIES = {
+ "numericFilter": {
+ "what": "Per-field numeric filter. Both spellings are live: the "
+ "lower-case dotted form and the older camel-case suffix "
+ "form. isComplexSetting() (hg/lib/trackDb.c:269) is the "
+ "authoritative list of these wildcard settings.",
+ "pattern": ["filter.<field>", "<field>Filter"],
+ "vars": [
+ v("filter.<field>", "float", "hg/inc/bigBedFilter.h:23",
+ note="Value, or 'min:max' colon pair."),
+ v("filter.<field>Min", "float", "hg/inc/hui.h:_MIN"),
+ v("filter.<field>Max", "float", "hg/inc/hui.h:_MAX"),
+ v("filterLimits.<field>", "string", "hg/lib/trackDb.c:282",
+ note="trackDb-side bounds; cart values outside them are "
+ "dropped (hg/hgTracks/bigBedTrack.c:88)."),
+ v("filterByRange.<field>", "bool", "hg/lib/trackDb.c:286"),
+ v("filterLabel.<field>", "string", "hg/inc/bigBedFilter.h:28"),
+ v("filterPriority.<field>", "float", "hg/inc/bigBedFilter.h:29"),
+ v("<field>FilterLimits", "string", "hg/lib/trackDb.c:298"),
+ v("<field>FilterPriority", "float", "hg/lib/trackDb.c:302"),
+ ],
+ },
+ "textFilter": {
+ "what": "Per-field text filter, wildcard or regex.",
+ "vars": [
+ v("filterText.<field>", "string", "hg/inc/bigBedFilter.h:24"),
+ v("filterType.<field>", "enum", "hg/inc/bigBedFilter.h:27",
+ values=["wildcard", "regexp"]),
+ v("<field>FilterText", "string", "hg/lib/trackDb.c:300"),
+ v("<field>FilterType", "enum", "hg/lib/trackDb.c:296"),
+ ],
+ },
+ "filterBy": {
+ "what": "Multi-select filter on a categorical field. Value 'All' "
+ "means no filtering.",
+ "vars": [
+ v("filterBy.<field>", "list", "hg/lib/hui.c:4058", multi=True),
+ v("filterValues.<field>", "string", "hg/inc/bigBedFilter.h:25",
+ note="trackDb-side value list."),
+ v("filterValuesDefault.<field>", "string",
+ "hg/inc/bigBedFilter.h:26"),
+ v("doAdvanced", "bool", "hg/lib/hui.c:filterBySetCfgUiGuts",
+ note="Advanced filter box expanded."),
+ ],
+ },
+ "highlightBy": {
+ "what": "Same shape as the filter family, but highlights instead of "
+ "hiding. Every filter* name has a highlight* twin.",
+ "vars": [
+ v("highlightBy.<field>", "list", "hg/lib/hui.c:4058", multi=True),
+ v("highlight.<field>", "float", "hg/inc/bigBedFilter.h:64"),
+ v("highlightText.<field>", "string", "hg/inc/bigBedFilter.h:65"),
+ v("highlightType.<field>", "enum", "hg/inc/bigBedFilter.h:68"),
+ v("highlightLimits.<field>", "string", "hg/lib/trackDb.c:...",
+ note="See isComplexSetting() for the full twin list."),
+ ],
+ },
+ "score": {
+ "what": "The old score-based filters, offered by scoreCfgUi for bed "
+ "and friends.",
+ "vars": [
+ v("scoreFilter", "int", "hg/lib/hui.c:scoreCfgUi",
+ tdb="scoreFilter"),
+ v("scoreFilterMin", "int", "hg/lib/hui.c:7268"),
+ v("scoreFilterMax", "int", "hg/lib/hui.c:7271"),
+ v("filterTopScorersOn", "bool", "hg/lib/hui.c:7301"),
+ v("filterTopScorersCt", "int", "hg/lib/hui.c:7307"),
+ v("minGrayLevel", "int", "hg/inc/hui.h:MIN_GRAY_LEVEL",
+ tdb="minGrayLevel"),
+ ],
+ },
+ "cds": {
+ "what": "Codon and base coloring, offered for every type that has "
+ "aligned or CDS-bearing items. hg/lib/hui.c:baseColorDropLists.",
+ "vars": [
+ v("baseColorDrawOpt", "enum", "hg/inc/hui.h:BASE_COLOR_VAR_SUFFIX",
+ values=["none", "genomicCodons", "itemCodons", "diffCodons",
+ "itemBases", "diffBases"]),
+ v("codonNumbering", "bool", "hg/inc/hui.h:CODON_NUMBERING_SUFFIX"),
+ v("showDiffBasesAllScales", "bool",
+ "hg/inc/hui.h:SHOW_DIFF_BASES_ALL_SCALES"),
+ v("baseColorUseCds", "string", "hg/inc/hui.h:BASE_COLOR_USE_CDS",
+ note="trackDb setting; read through cartOrTdb."),
+ v("baseColorUseSequence", "string",
+ "hg/inc/hui.h:BASE_COLOR_USE_SEQUENCE",
+ note="trackDb setting; read through cartOrTdb."),
+ ],
+ },
+ "indel": {
+ "what": "Indel display, alignment types. "
+ "hg/lib/hui.c:indelShowOptionsWithNameExt.",
+ "vars": [
+ v("indelDoubleInsert", "bool", "hg/inc/hui.h:INDEL_DOUBLE_INSERT"),
+ v("indelQueryInsert", "bool", "hg/inc/hui.h:INDEL_QUERY_INSERT"),
+ v("indelPolyA", "bool", "hg/inc/hui.h:INDEL_POLY_A"),
+ ],
+ },
+ "label": {
+ "what": "Which label to draw. Legacy tracks each grew their own "
+ "checkbox set, which is why the same idea appears under so "
+ "many names. hg/lib/hui.c:labelCfgUi is the modern one.",
+ "vars": [
+ v("label", "list", "hg/lib/hui.c:labelMakeCheckBox", multi=True,
+ tdb="labelFields",
+ note="Modern bigBed form: one entry per chosen field."),
+ v("label.gene", "bool", "hg/hgTracks/retroGene.c:121"),
+ v("label.acc", "bool", "hg/hgTracks/transMapTracks.c:48"),
+ v("label.orgCommon", "bool", "hg/hgTracks/transMapTracks.c:50"),
+ v("accLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1511"),
+ v("geneLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1510"),
+ v("posLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1513"),
+ v("sprotLabel", "bool", "hg/hgTrackUi/hgTrackUi.c:1512"),
+ ],
+ },
+ "gencodeShow": {
+ "what": "GENCODE / knownGene transcript-set filters.",
+ "vars": [
+ v("show.set", "enum", "hg/lib/hui.c:newGencodeShowOptions"),
+ v("show.noncoding", "bool", "hg/lib/hui.c:newGencodeShowOptions"),
+ v("show.pseudo", "bool", "hg/lib/hui.c:newGencodeShowOptions"),
+ v("show.spliceVariants", "bool",
+ "hg/lib/hui.c:newGencodeShowOptions"),
+ v("show.comprehensive", "bool",
+ "hg/hgTrackUi/hgTrackUi.c:1747"),
+ v("hideNoncoding", "bool", "hg/inc/hui.h:HIDE_NONCODING_SUFFIX"),
+ v("maxTrans", "int", "hg/lib/hui.c:gencodeMaxTransControl"),
+ ],
+ },
+ "decorator": {
+ "what": "A decorator is a nested namespace inside the track: "
+ "<track>.decorator.<decoratorName>.<var>. "
+ "hg/lib/decoratorUi.c gins up a fake tdb so the filter "
+ "families above work unchanged inside it.",
+ "prefix": "decorator.<decoratorName>.",
+ "vars": [
+ v("decorator.<name>.blockMode", "enum",
+ "hg/lib/decoratorUi.c:21",
+ values=["Hide", "Overlay", "Adjacent"], default="Overlay"),
+ v("decorator.<name>.glyphMode", "enum",
+ "hg/lib/decoratorUi.c:23",
+ values=["Hide", "Overlay", "Adjacent"], default="Overlay"),
+ v("decorator.<name>.Overlaytoggle", "bool",
+ "hg/lib/decoratorUi.c:19",
+ note="Draw labels for blocks in overlay mode."),
+ v("decorator.<name>.maxLabelBases", "int",
+ "hg/lib/decoratorUi.c:26", default="200000"),
+ v("decorator.<name>.filterBy.<field>", "list",
+ "hg/lib/decoratorUi.c:176", multi=True,
+ note="Whole filterBy family nests here."),
+ ],
+ },
+ "species": {
+ "what": "Per-species on/off, used by maf/wigMaf and by chain/net "
+ "cross-species coloring.",
+ "vars": [
+ v("<species>", "bool", "hg/lib/hui.c:isSpeciesOn",
+ note="One var per species in the maf, name is the db or "
+ "species name itself."),
+ v("speciesOrder", "string", "hg/hgc/mafClick.c:609"),
+ ],
+ },
+}
+
+# ---------------------------------------------------------------------------
+# LEVEL 3: the type layer. Keyed by eCfgType where one exists
+# (hg/inc/trackDb.h:439) plus the types that fall through cfgByCfgType.
+# ---------------------------------------------------------------------------
+
+TYPES = {
+ "wig": {
+ "cfgType": "cfgWig",
+ "tdbTypes": ["wig", "bigWig", "bedGraph", "mathWig", "instaPort"],
+ "cfgUi": "hg/lib/hui.c:wigCfgUi",
+ "cart": "hg/lib/wiggleCart.c",
+ "families": [],
+ "vars": [
+ v("minY", "float", "hg/inc/wiggle.h:MIN_Y", tdb="viewLimits"),
+ v("maxY", "float", "hg/inc/wiggle.h:MAX_Y", tdb="viewLimits"),
+ v("autoScale", "enum", "hg/inc/wiggle.h:AUTOSCALE",
+ values=["on", "off", "group", "cumulative"],
+ tdb="autoScaleDefault"),
+ v("alwaysZero", "enum", "hg/inc/wiggle.h:ALWAYSZERO",
+ values=["on", "off"]),
+ v("lineBar", "enum", "hg/inc/wiggle.h:LINEBAR",
+ values=["Bar", "Points"], tdb="graphTypeDefault"),
+ v("transformFunc", "enum", "hg/inc/wiggle.h:TRANSFORMFUNC",
+ values=["NONE", "LOG"]),
+ v("negateValues", "bool", "hg/inc/wiggle.h:DONEGATIVEMODE"),
+ v("sequenceLogo", "bool", "hg/inc/wiggle.h:DOSEQUENCELOGOMODE"),
+ v("horizGrid", "enum", "hg/inc/wiggle.h:HORIZGRID",
+ values=["on", "off"], tdb="gridDefault"),
+ v("yLineOnOff", "enum", "hg/inc/wiggle.h:YLINEONOFF",
+ values=["on", "off"]),
+ v("yLineMark", "float", "hg/inc/wiggle.h:YLINEMARK"),
+ v("smoothingWindow", "enum", "hg/inc/wiggle.h:SMOOTHINGWINDOW",
+ values=["off", "2", "3", "4", "...", "16"]),
+ v("windowingFunction", "enum",
+ "hg/inc/wiggle.h:WINDOWINGFUNCTION",
+ values=["mean+whiskers", "maximum", "mean", "minimum", "sum"]),
+ v("aggregate", "enum", "hg/inc/wiggle.h:AGGREGATE",
+ values=["none", "transparentOverlay", "solidOverlay",
+ "stacked", "add", "subtract"],
+ note="Container-level, but readable at leaf level too."),
+ v("viewFunc", "enum", "hg/inc/wiggle.h:VIEWFUNC",
+ values=["showAll", "addAll", "subtractAll"]),
+ v("missingMethod", "enum", "hg/lib/hui.c:6257",
+ note="How to render gaps in the data."),
+ v("heightPer", "int", "hg/inc/wiggle.h:HEIGHTPER", default="128"),
+ ],
+ "tdbOnly": ["viewLimits", "viewLimitsMax", "defaultViewLimits",
+ "minLimit", "maxLimit", "maxHeightPixels", "gridDefault",
+ "autoScaleDefault", "graphType", "graphTypeDefault",
+ "spanList"],
+ },
+ "bedScore": {
+ "cfgType": "cfgBedScore",
+ "tdbTypes": ["bed", "bigBed", "bed<n> +", "bigNarrowPeak", "broadPeak"],
+ "cfgUi": "hg/lib/hui.c:bedScoreCfgUi",
+ "families": ["score", "numericFilter", "textFilter", "filterBy",
+ "highlightBy", "label", "cds", "decorator"],
+ "vars": [
+ v("colorField", "string", "hg/lib/hui.c:colorFieldsCfgUi",
+ tdb="colorByStrand"),
+ v("scoreLabel", "string", "hg/inc/hui.h:SCORE_LABEL"),
+ ],
+ "tdbOnly": ["noScoreFilter", "scoreMin", "labelFields",
+ "defaultLabelFields"],
+ },
+ "bedFilt": {
+ "cfgType": "cfgBedFilt",
+ "tdbTypes": ["bed (mrna-style filters)"],
+ "cfgUi": "hg/lib/hui.c:bedFiltCfgUi",
+ "families": [],
+ "vars": [
+ v("<filterName>", "string", "hg/lib/hui.c:bedFiltCfgUi",
+ note="One var per filter declared in the track's mrnaUiData "
+ "(hg/hgTracks/bedTrack.c:427)."),
+ v("<filterName>Type", "enum", "hg/hgTracks/bedTrack.c:434",
+ values=["include", "exclude"]),
+ v("<filterName>Logic", "enum", "hg/hgTracks/bedTrack.c:441",
+ values=["and", "or"]),
+ ],
+ },
+ "peak": {
+ "cfgType": "cfgPeak",
+ "tdbTypes": ["encodePeak", "narrowPeak", "broadPeak", "gappedPeak"],
+ "cfgUi": "hg/lib/hui.c:encodePeakCfgUi",
+ "families": ["score", "numericFilter"],
+ "vars": [
+ v("signalFilter", "float", "hg/inc/hui.h:SIGNAL_FILTER"),
+ v("signalFilterLimits", "string", "hg/inc/hui.h:_LIMITS"),
+ v("pValueFilter", "float", "hg/inc/hui.h:PVALUE_FILTER"),
+ v("qValueFilter", "float", "hg/inc/hui.h:QVALUE_FILTER"),
+ ],
+ },
+ "genePred": {
+ "cfgType": "cfgGenePred",
+ "tdbTypes": ["genePred", "bigGenePred"],
+ "cfgUi": "hg/lib/hui.c:genePredCfgUi",
+ "families": ["cds", "indel", "label", "gencodeShow", "numericFilter",
+ "filterBy", "score", "decorator"],
+ "vars": [
+ v("type", "enum", "hg/lib/hui.c:genePredCfgUi",
+ note="Which of several gene ID sources to label with."),
+ v("geneClasses", "string", "hg/inc/hui.h:GENEPRED_CLASS_VAR",
+ note="trackDb-declared class list; per-class colors are the "
+ "trackDb settings gClass_<class>, not cart vars."),
+ v("itemClassTbl", "string", "hg/inc/hui.h:GENEPRED_CLASS_TBL"),
+ ],
+ },
+ "psl": {
+ "cfgType": "cfgPsl",
+ "tdbTypes": ["psl", "bigPsl", "psl xeno <db>", "chain (via snake)"],
+ "cfgUi": "hg/lib/hui.c:pslCfgUi",
+ "families": ["cds", "indel", "score", "label"],
+ "vars": [
+ v("color", "enum", "hg/lib/hui.c:crossSpeciesCfgUi",
+ values=["on", "off"],
+ note="Chromosome coloring for cross-species psl. Default "
+ "'on' unless trackDb colorChromDefault off."),
+ v("showPatentSequences", "bool",
+ "hg/inc/hui.h:SHOW_PATENT_SEQUENCES_SUFFIX"),
+ v("chromFilter", "string",
+ "hg/hgTracks/pslTrack.c:connectedLfFromPslsInRange"),
+ v("pslSequenceBases", "string", "hg/inc/hui.h:PSL_SEQUENCE_BASES",
+ default="no"),
+ ],
+ },
+ "chain": {
+ "cfgType": "cfgChain",
+ "tdbTypes": ["chain", "bigChain"],
+ "cfgUi": "hg/lib/hui.c:chainCfgUi",
+ "families": ["score"],
+ "vars": [
+ v("chainColor", "enum", "hg/inc/chainCart.h:OPT_CHROM_COLORS",
+ values=["Chromosome", "Normalized Score", "Black"]),
+ v("chromFilter", "string", "hg/inc/chainCart.h:OPT_CHROM_FILTER",
+ note="Restrict to chains against one query chrom."),
+ v("color", "enum", "hg/lib/hui.c:chainCfgUi",
+ values=["on", "off"],
+ note="Cross-species chromosome coloring, shared with psl."),
+ ],
+ "tdbOnly": ["chainNormScoreAvailable"],
+ },
+ "net": {
+ "cfgType": "cfgNetAlign",
+ "tdbTypes": ["netAlign"],
+ "cfgUi": "hg/lib/hui.c:netAlignCfgUi",
+ "families": [],
+ "vars": [
+ v("netColor", "enum", "hg/inc/netCart.h:NET_COLOR",
+ values=["Chromosome", "Gray scale"]),
+ v("netLevel", "enum", "hg/inc/netCart.h:NET_LEVEL",
+ values=["All levels", "level 1 only", "level 2 only",
+ "level 3 only", "level 4 only", "level 5 only",
+ "level 6 only"]),
+ v("netTopOnly", "bool", "hg/inc/hui.h:NET_OPT_TOP_ONLY"),
+ ],
+ },
+ "wigMaf": {
+ "cfgType": "cfgWigMaf",
+ "tdbTypes": ["wigMaf", "bigMaf", "maf"],
+ "cfgUi": "hg/lib/hui.c:wigMafCfgUi",
+ "families": ["species", "wig (embedded conservation wiggle)"],
+ "vars": [
+ v("mafDot", "bool", "hg/inc/hui.h:MAF_DOT_VAR",
+ note="Show dots for matching bases."),
+ v("mafChain", "bool", "hg/inc/hui.h:MAF_CHAIN_VAR",
+ note="Display chains between blocks."),
+ v("mafShowSnp", "bool", "hg/inc/hui.h:MAF_SHOW_SNP"),
+ v("mafGenePred", "string", "hg/inc/hui.h:MAF_GENEPRED_VAR",
+ note="Gene track used for codon translation."),
+ v("mafFrame", "enum", "hg/inc/hui.h:MAF_FRAMING_VAR"),
+ v("codons", "enum", "hg/hgTracks/wigMafTrack.c:2085"),
+ v("frames", "string", "hg/hgTracks/wigMafTrack.c:2079"),
+ v("baseColors", "string", "hg/hgTracks/wigMafTrack.c:2405"),
+ v("baseColorsOffset", "int",
+ "hg/hgTracks/wigMafTrack.c:2407"),
+ v("<wigTrack>.<wigVar>", "varies",
+ "hg/hgTracks/wigMafTrack.c:2760",
+ note="The conservation wiggle is configured as a nested "
+ "namespace under the wigMaf track."),
+ ],
+ },
+ "bam": {
+ "cfgType": "cfgBam",
+ "tdbTypes": ["bam", "cram"],
+ "cfgUi": "hg/lib/hui.c:bamCfgUi",
+ "families": ["cds", "indel", "wig (when bamWigMode is on)"],
+ "vars": [
+ v("pairEndsByName", "bool", "hg/inc/hui.h:BAM_PAIR_ENDS_BY_NAME"),
+ v("showNames", "bool", "hg/inc/hui.h:BAM_SHOW_NAMES"),
+ v("minAliQual", "int", "hg/inc/hui.h:BAM_MIN_ALI_QUAL",
+ default="0"),
+ v("bamColorMode", "enum", "hg/inc/hui.h:BAM_COLOR_MODE",
+ values=["gray", "strand", "tag", "off"], default="strand"),
+ v("bamGrayMode", "enum", "hg/inc/hui.h:BAM_GRAY_MODE",
+ values=["aliQual", "baseQual", "unpaired"], default="aliQual"),
+ v("bamColorTag", "string", "hg/inc/hui.h:BAM_COLOR_TAG",
+ default="YC"),
+ v("bamWigMode", "bool", "hg/inc/hui.h:BAMWIG_MODE",
+ note="Draw coverage as a wiggle; pulls in the wig group."),
+ ],
+ },
+ "vcf": {
+ "cfgType": "cfgVcf",
+ "tdbTypes": ["vcfTabix", "vcf", "vcfPhasedTrio"],
+ "cfgUi": "hg/lib/vcfUi.c:vcfCfgUi",
+ "families": ["filterBy"],
+ "vars": [
+ v("hapClusterEnabled", "bool", "hg/inc/vcfUi.h:16"),
+ v("hapClusterHeight", "int", "hg/inc/vcfUi.h:13"),
+ v("hapClusterMethod", "enum", "hg/inc/vcfUi.h:17",
+ values=["centerWeighted", "fileOrder", "treeFile"]),
+ v("hapClusterColorBy", "enum", "hg/inc/vcfUi.h:23",
+ values=["altOnly", "function", "refAlt", "base"]),
+ v("hapClusterTreeAngle", "enum", "hg/inc/vcfUi.h:30",
+ values=["triangle", "rectangle"]),
+ v("sampleColorFile", "string", "hg/inc/vcfUi.h:35"),
+ v("applyMinQual", "bool", "hg/inc/vcfUi.h:40"),
+ v("minQual", "float", "hg/inc/vcfUi.h:44"),
+ v("minFreq", "float", "hg/inc/vcfUi.h:52"),
+ v("excludeFilterValues", "list", "hg/inc/vcfUi.h:49", multi=True),
+ v("showHardyWeinberg", "bool", "hg/inc/vcfUi.h:38"),
+ v("vcfSampleOrder", "string", "hg/inc/vcfUi.h:57",
+ note="Drag-and-drop sample order, comma separated."),
+ v("doDefaultLabel", "bool", "hg/inc/vcfUi.h:59"),
+ v("doAliasLabel", "bool", "hg/inc/vcfUi.h:60"),
+ v("hideParents", "bool", "hg/inc/vcfUi.h:61"),
+ v("sortChildBelow", "bool", "hg/inc/vcfUi.h:63"),
+ v("vcfPhasedColorBy", "enum", "hg/inc/vcfUi.h:65",
+ values=["mendelDiff", "deNovo", "function", "noColor"]),
+ v("centerVariantChrom", "hidden", "hg/lib/vcfUi.c:33",
+ note="Haplotype-sorting anchor. Position state stored on the "
+ "track, which is unusual and worth flagging in a "
+ "rewrite."),
+ v("centerVariantPos", "hidden", "hg/lib/vcfUi.c:35"),
+ v("centerVariantName", "hidden", "hg/lib/vcfUi.c:39"),
+ ],
+ },
+ "snake": {
+ "cfgType": "cfgSnake",
+ "tdbTypes": ["halSnake", "chain (snake mode)", "pslSnake"],
+ "cfgUi": "hg/lib/snakeUi.c:snakeCfgUi",
+ "families": ["score"],
+ "vars": [
+ v("showSnpWidth", "int", "hg/inc/snakeUi.h:12"),
+ v("colorBy", "enum", "hg/inc/snakeUi.h:24",
+ values=["byStrand", "byChromosome", "none"]),
+ v("chromFilter", "string",
+ "hg/hgTracks/halSnakeTrack.c:snakeLoadItems"),
+ v("coalescent", "string", "hg/hgTracks/halSnakeTrack.c:1764",
+ note="HAL only."),
+ v("color", "enum", "hg/hgTracks/halSnakeTrack.c:snakeMethods"),
+ ],
+ },
+ "long": {
+ "cfgType": "cfgLong",
+ "tdbTypes": ["longTabix"],
+ "cfgUi": "hg/lib/longRange.c:longRangeCfgUi",
+ "families": [],
+ "vars": [
+ v("heightPer", "int", "hg/inc/longRange.h:14", default="200"),
+ v("minScore", "float", "hg/inc/longRange.h:18", default="0"),
+ ],
+ },
+ "interact": {
+ "cfgType": "cfgInteract",
+ "tdbTypes": ["interact", "bigInteract"],
+ "cfgUi": "hg/lib/interactUi.c:interactCfgUi",
+ "families": ["score", "filterBy"],
+ "vars": [
+ v("heightPer", "int", "hg/inc/interactUi.h:9", default="200"),
+ v("minScore", "float", "hg/inc/interactUi.h:13"),
+ v("draw", "enum", "hg/inc/interactUi.h:38",
+ values=["line", "ellipse", "curve"]),
+ v("dashes", "bool", "hg/inc/interactUi.h:35",
+ note="Dash the line to show direction."),
+ v("endsVisible", "enum", "hg/inc/interactUi.h:44",
+ values=["two", "one", "any"]),
+ v("cluster", "enum", "hg/inc/interactUi.h:50",
+ values=["none", "source", "target"]),
+ v("detailsBoxesEnabled", "bool", "hg/inc/interactUi.h:31"),
+ ],
+ "tdbOnly": ["interactDirectional", "offsetSource", "offsetTarget",
+ "clusterSource", "clusterTarget", "interactUp"],
+ },
+ "hic": {
+ "cfgType": "cfgHic",
+ "tdbTypes": ["hic"],
+ "cfgUi": "hg/lib/hicUi.c:hicCfgUi",
+ "families": [],
+ "vars": [
+ v("drawMode", "enum", "hg/inc/hicUi.h:31",
+ values=["triangle", "square", "arc"]),
+ v("inverted", "bool", "hg/inc/hicUi.h:36"),
+ v("normalization", "string", "hg/inc/hicUi.h:37"),
+ v("resolution", "string", "hg/inc/hicUi.h:38"),
+ v("autoscale", "bool", "hg/inc/hicUi.h:39",
+ note="Lower case, unlike the wig autoScale."),
+ v("max", "float", "hg/inc/hicUi.h:40", tdb="saturationScore"),
+ v("color", "color", "hg/inc/hicUi.h:42", default="#ff0000"),
+ v("bgColor", "color", "hg/inc/hicUi.h:43", default="#ffffff"),
+ v("maxDistance", "int", "hg/inc/hicUi.h:47",
+ tdb="hicDistanceMax"),
+ v("minDistance", "int", "hg/inc/hicUi.h:48",
+ tdb="hicDistanceMin"),
+ v("hicArcLimit", "int", "hg/inc/hicUi.h:50"),
+ v("hicArcLimitEnabled", "bool", "hg/inc/hicUi.h:51"),
+ ],
+ },
+ "barChart": {
+ "cfgType": "cfgBarChart",
+ "tdbTypes": ["barChart", "bigBarChart"],
+ "cfgUi": "hg/lib/barChartUi.c:barChartCfgUi",
+ "families": ["score", "filterBy", "label"],
+ "vars": [
+ v("colorScheme", "enum", "hg/inc/barChartUi.h:13",
+ values=["rainbow", "user"]),
+ v("logTransform", "bool", "hg/inc/barChartUi.h:22"),
+ v("maxViewLimit", "float", "hg/inc/barChartUi.h:29",
+ tdb="maxLimit"),
+ v("categories", "list", "hg/inc/barChartUi.h:38", multi=True,
+ note="Which categories to show; 'All' means every one."),
+ v("noWhiteout", "bool", "hg/inc/barChartUi.h:58"),
+ ],
+ "tdbOnly": ["barChartBars", "barChartLabel", "barChartColors",
+ "barChartCategoryUrl", "barChartUnit", "barChartMetric",
+ "barChartMaxSize", "barChartSizeWindows",
+ "barChartBarMinWidth", "barChartBarMinPadding",
+ "barChartLimit"],
+ },
+ "lolly": {
+ "cfgType": "cfgLollipop",
+ "tdbTypes": ["bigLolly"],
+ "cfgUi": "hg/lib/hui.c:lollyCfgUi",
+ "families": ["score", "numericFilter", "filterBy", "label"],
+ "vars": [
+ v("heightPer", "int", "hg/lib/hui.c:lollyCfgUi"),
+ v("autoScale", "enum", "hg/lib/hui.c:lollyCfgUi",
+ values=["on", "off"]),
+ v("minY", "float", "hg/lib/hui.c:lollyCfgUi"),
+ v("maxY", "float", "hg/lib/hui.c:lollyCfgUi"),
+ v("popMethod", "enum", "hg/lib/hui.c:lollyCfgUi",
+ tdb="popMethod"),
+ ],
+ },
+ "bigDbSnp": {
+ "cfgType": "cfgBigDbSnp",
+ "tdbTypes": ["bigDbSnp"],
+ "cfgUi": "hg/lib/hui.c:bigDbSnpCfgUi",
+ "families": ["filterBy", "label"],
+ "vars": [
+ v("minMaf", "float", "hg/lib/hui.c:4954"),
+ v("freqProj", "enum", "hg/lib/hui.c:freqSourceSelect",
+ note="Which frequency project supplies MAF."),
+ v("label.rsId", "bool", "hg/hgTracks/variation.c:2712"),
+ v("label.majMin", "bool", "hg/hgTracks/variation.c:2723"),
+ v("label.refAlt", "bool", "hg/hgTracks/variation.c:2715"),
+ v("label.func", "bool", "hg/hgTracks/variation.c:2737"),
+ v("label.maf", "bool", "hg/hgTracks/variation.c:2730"),
+ v("geneTrack", "string", "hg/lib/hui.c:4881"),
+ v("geneTracks", "list", "hg/lib/hui.c:4875", multi=True),
+ ],
+ },
+ "bigRmsk": {
+ "cfgType": "cfgBigRmsk",
+ "tdbTypes": ["bigRmsk"],
+ "cfgUi": "hg/lib/hui.c:bigRmskCfgUi",
+ "families": [],
+ "prefix": "bigrmsk.",
+ "vars": [
+ v("bigrmsk.showUnalignedExtents", "bool",
+ "hg/inc/bigRmskUi.h:10"),
+ v("bigrmsk.showLabels", "bool", "hg/inc/bigRmskUi.h:14"),
+ v("bigrmsk.origPackViz", "bool", "hg/inc/bigRmskUi.h:18"),
+ v("bigrmsk.nameFilter", "string", "hg/inc/bigRmskUi.h:22",
+ default="*"),
+ v("bigrmsk.regexpFilter", "string", "hg/inc/bigRmskUi.h:26"),
+ ],
+ },
+ "gtexGene": {
+ "cfgType": "(cfgBedScore plus gtexGeneUi)",
+ "tdbTypes": ["bed 12 + (gtexGene*)"],
+ "cfgUi": "hg/lib/gtexUi.c:gtexGeneUi",
+ "families": ["score"],
+ "vars": [
+ v("colorScheme", "enum", "hg/inc/gtexUi.h:9",
+ values=["rainbow", "gtex"]),
+ v("logTransform", "bool", "hg/inc/gtexUi.h:18"),
+ v("maxViewLimit", "float", "hg/inc/gtexUi.h:23"),
+ v("samples", "enum", "hg/inc/gtexUi.h:29",
+ values=["all", "sex", "age"]),
+ v("comparison", "enum", "hg/inc/gtexUi.h:39",
+ values=["mirror", "difference"]),
+ v("graphType", "enum", "hg/inc/gtexUi.h:45",
+ values=["raw", "normalized"]),
+ v("tissues", "list", "hg/inc/gtexUi.h:51", multi=True),
+ v("codingOnly", "bool", "hg/inc/gtexUi.h:54"),
+ v("showExons", "bool", "hg/inc/gtexUi.h:58"),
+ v("noWhiteout", "bool", "hg/inc/gtexUi.h:62"),
+ v("label", "enum", "hg/inc/gtexUi.h:66",
+ values=["name", "accession", "both"]),
+ ],
+ },
+ "gtexEqtlCluster": {
+ "cfgType": "(cfgBedScore plus gtexEqtlClusterUi)",
+ "tdbTypes": ["bed 9 + (gtexEqtlCluster*)"],
+ "cfgUi": "hg/lib/gtexUi.c:gtexEqtlClusterUi",
+ "families": ["score"],
+ "vars": [
+ v("effect", "float", "hg/inc/gtexUi.h:74"),
+ v("prob", "float", "hg/inc/gtexUi.h:76"),
+ v("gene", "string", "hg/inc/gtexUi.h:78"),
+ v("tissueColor", "bool", "hg/inc/gtexUi.h:79"),
+ v("tissues", "list", "hg/inc/gtexUi.h:51", multi=True),
+ ],
+ },
+ "expRatio": {
+ "cfgType": "(falls through cfgByCfgType)",
+ "tdbTypes": ["expRatio", "array"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:expRatioUi",
+ "families": [],
+ "vars": [
+ v("color", "enum", "hg/hgTrackUi/hgTrackUi.c:1360",
+ note="Red/green vs blue/yellow etc."),
+ v("type", "enum", "hg/hgTracks/expRatioTracks.c:lfsFromAffyBed"),
+ v("combine", "enum", "hg/lib/microarray.c:1167"),
+ v("subset", "enum", "hg/lib/microarray.c:1174"),
+ v("expDrawExons", "bool", "hg/hgTrackUi/hgTrackUi.c:1347"),
+ v("heightPer", "int", "hg/hgTrackUi/hgTrackUi.c:2026"),
+ ],
+ },
+ "sample": {
+ "cfgType": "(falls through cfgByCfgType)",
+ "tdbTypes": ["sample"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:genericWiggleUi",
+ "families": [],
+ "vars": [
+ v("heightPer", "int", "hg/hgTracks/sampleTracks.c:sampleTotalHeight"),
+ v("min.cutoff", "float", "hg/hgTrackUi/hgTrackUi.c:2029"),
+ v("max.cutoff", "float", "hg/hgTrackUi/hgTrackUi.c:2030"),
+ v("linear.interp", "enum", "hg/hgTrackUi/hgTrackUi.c:2027"),
+ v("interp.gap", "int", "hg/hgTrackUi/hgTrackUi.c:2031"),
+ v("fill", "bool", "hg/hgTrackUi/hgTrackUi.c:2028"),
+ v("anti.alias", "bool", "hg/hgTracks/sampleTracks.c:272"),
+ ],
+ },
+ "chromGraph": {
+ "cfgType": "(falls through cfgByCfgType)",
+ "tdbTypes": ["chromGraph"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:chromGraphUi",
+ "families": [],
+ "note": "Exception: names are cgs_<track>_<var>, prefix first. See "
+ "the exceptions section.",
+ "vars": [
+ v("pixels", "int", "hg/lib/chromGraph.c:chromGraphVarName",
+ sep="cgs_<track>_"),
+ v("minVal", "float", "hg/lib/chromGraph.c:301",
+ sep="cgs_<track>_"),
+ v("maxVal", "float", "hg/lib/chromGraph.c:303",
+ sep="cgs_<track>_"),
+ v("maxGapToFill", "int", "hg/lib/chromGraph.c:299",
+ sep="cgs_<track>_"),
+ ],
+ },
+ "factorSource": {
+ "cfgType": "(falls through cfgByCfgType)",
+ "tdbTypes": ["factorSource"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:factorSourceUi",
+ "families": ["score", "filterBy"],
+ "vars": [
+ v("highlightMotifs", "bool", "hg/hgTrackUi/hgTrackUi.c:2778"),
+ v("showCellAbbrevs", "bool", "hg/hgTrackUi/hgTrackUi.c:2789"),
+ v("showExpCounts", "bool", "hg/hgTrackUi/hgTrackUi.c:2785"),
+ ],
+ },
+ "ld": {
+ "cfgType": "(name/type special case)",
+ "tdbTypes": ["ld2", "hapmapLd*", "rertyHumanDiversityLd"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:ldUi",
+ "families": [],
+ "note": "All underscore-separated, one of the oldest var sets.",
+ "vars": [
+ v("_val", "enum", "hg/hgTracks/variation.c:ldDrawItems", sep="_",
+ values=["rsquared", "dprime", "lod"]),
+ v("_trm", "bool", "hg/hgTracks/variation.c:ldDrawItems", sep="_",
+ note="Trim to triangle."),
+ v("_inv", "bool", "hg/hgTracks/variation.c:ldDrawItems", sep="_",
+ note="Invert the display."),
+ v("_pos", "color", "hg/hgTracks/variation.c:ldShadesInit",
+ sep="_"),
+ v("_out", "enum", "hg/hgTracks/variation.c:getOutlineColor",
+ sep="_"),
+ v("_gap", "bool", "hg/hgTracks/variation.c:ldDrawDense", sep="_"),
+ ],
+ },
+ "gvf": {
+ "cfgType": "(falls through cfgByCfgType)",
+ "tdbTypes": ["gvf"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:gvUi",
+ "families": [],
+ "vars": [
+ v("_<origin>", "bool", "hg/hgTracks/gvfTrack.c:gvfItemName",
+ sep="_",
+ note="One per variant origin: _germ _som _dnovo _bip _mat "
+ "_pat _unip _unk."),
+ ],
+ },
+ "snp125": {
+ "cfgType": "(name special case, snpVersion >= 125)",
+ "tdbTypes": ["snp125 .. snp15x"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:snp125Ui",
+ "families": [],
+ "vars": [
+ v("include_<attribute>", "list",
+ "hg/cgilib/snp125Ui.c:605", multi=True,
+ note="Attribute is one of molType class valid func locType "
+ "exceptions bitfields. Values are the kept categories."),
+ v("colorSource", "enum", "hg/cgilib/snp125Ui.c:687",
+ values=["locType", "class", "valid", "func", "molType",
+ "exceptions", "bitfields", "alleleFreq"]),
+ v("<attribute><Value>", "color",
+ "hg/hgTrackUi/hgTrackUi.c:snp125RemoveColorVars",
+ note="One color var per attribute value, e.g. "
+ "<track>.funcMissense. Nested leaf level keyed by "
+ "attribute then value."),
+ v("minAvHet", "float", "hg/hgTrackUi/hgTrackUi.c:416"),
+ v("maxWeight", "int", "hg/hgTrackUi/hgTrackUi.c:424"),
+ v("minSubmitters", "int", "hg/hgTrackUi/hgTrackUi.c:440"),
+ v("minMinorAlFreq", "float", "hg/hgTrackUi/hgTrackUi.c:444"),
+ v("maxMinorAlFreq", "float", "hg/hgTrackUi/hgTrackUi.c:448"),
+ v("minAlFreq2N", "int", "hg/hgTrackUi/hgTrackUi.c:455"),
+ v("extendedNames", "bool", "hg/hgTrackUi/hgTrackUi.c:726"),
+ v("allelesDbSnpStrand", "bool", "hg/hgTrackUi/hgTrackUi.c:745"),
+ ],
+ },
+ "blast": {
+ "cfgType": "(name special case)",
+ "tdbTypes": ["blastHg*KG, blastDm*, blastSacCer1SG, mrnaMap*, "
+ "mrnaXeno*"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:blastUi",
+ "families": ["label", "cds"],
+ "vars": [
+ v("cmode", "enum", "hg/hgTracks/simpleTracks.c:blastColor",
+ note="Color mode: black, by identity, by species."),
+ ],
+ },
+ "pubs": {
+ "cfgType": "(name special case, startsWith pubs)",
+ "tdbTypes": ["pubs*"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:pubsUi",
+ "families": [],
+ "vars": [
+ v("pubsFilterKeywords", "string",
+ "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"),
+ v("pubsFilterYear", "string",
+ "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"),
+ v("pubsFilterPublisher", "string",
+ "hg/hgTracks/pubsTracks.c:pubsLoadKeywordYearItems"),
+ v("pubsColorBy", "enum", "hg/hgTracks/pubsTracks.c:pubsMakeExtra"),
+ ],
+ },
+ "transMap": {
+ "cfgType": "(name special case, transMapAln*)",
+ "tdbTypes": ["psl (transMap)"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:transMapUI",
+ "families": ["label", "cds", "indel"],
+ "vars": [],
+ },
+ "retroGene": {
+ "cfgType": "(name special case, ucscRetro*, retroMrnaInfo*)",
+ "tdbTypes": ["psl (retro)"],
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:retroGeneUI",
+ "families": ["label", "cds", "indel"],
+ "vars": [],
+ },
+ "mrna": {
+ "cfgType": "(name special case: mrna, est, xenoMrna, intronEst, ...)",
+ "tdbTypes": ["psl"],
+ "cfgUi": "hg/lib/hui.c:mrnaCfgUi",
+ "families": ["cds", "indel", "bedFilt"],
+ "vars": [],
+ },
+}
+
+# ---------------------------------------------------------------------------
+# LEVEL 3b: tracks whose vars are written as literals rather than composed
+# from tdb->track. They still sit under <track>., so they belong in the
+# hierarchy, but grep for the suffix alone will not find them.
+# ---------------------------------------------------------------------------
+
+BY_TRACK_NAME = {
+ "stsMap": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:stsMapUi",
+ "vars": [
+ v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:91",
+ values=["blue", "red", "green", "black"]),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:91"),
+ ],
+ },
+ "stsMapMouseNew / stsMapRat": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:stsMapMouseUi",
+ "vars": [
+ v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:101"),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:101"),
+ ],
+ },
+ "cbr_waba": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:cbrWabaUi",
+ "vars": [
+ v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:1223"),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1223"),
+ v("start", "int", "hg/hgTrackUi/hgTrackUi.c:1223"),
+ v("end", "int", "hg/hgTrackUi/hgTrackUi.c:1223"),
+ ],
+ },
+ "fishClones": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:fishClonesUi",
+ "vars": [
+ v("filter", "enum", "hg/hgTrackUi/hgTrackUi.c:1236"),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1236"),
+ ],
+ },
+ "recombRate / recombRateRat / recombRateMouse": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:recombRateUi",
+ "vars": [v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1246")],
+ },
+ "cghNci60": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:cghNci60Ui",
+ "vars": [
+ v("color", "enum", "hg/hgTrackUi/hgTrackUi.c:1270",
+ values=["rg", "rb", "gr"]),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1270"),
+ ],
+ },
+ "rosetta": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:rosettaUi",
+ "vars": [
+ v("et", "enum", "hg/hgTrackUi/hgTrackUi.c:1456"),
+ v("type", "enum", "hg/hgTrackUi/hgTrackUi.c:1456"),
+ ],
+ },
+ "switchDbTss": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:switchDbScoreUi",
+ "vars": [
+ v("scoreFilter", "int", "hg/hgTrackUi/hgTrackUi.c:1475",
+ default="10"),
+ v("pseudo", "bool", "hg/hgTrackUi/hgTrackUi.c:1475"),
+ ],
+ },
+ "affyTranscriptome": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:affyTranscriptomeUi",
+ "vars": [
+ v("fill", "bool", "hg/hgTrackUi/hgTrackUi.c:2479"),
+ v("heightPer", "int", "hg/hgTrackUi/hgTrackUi.c:2479",
+ default="100"),
+ ],
+ },
+ "ancientR": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:ancientRUi",
+ "vars": [v("minLength", "int", "hg/hgTrackUi/hgTrackUi.c:2500",
+ default="50")],
+ },
+ "affyTransfrags": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:affyTransfragUi",
+ "vars": [
+ v("skipDups", "bool", "hg/hgTrackUi/hgTrackUi.c:2511"),
+ v("skipPseudos", "bool", "hg/hgTrackUi/hgTrackUi.c:2511"),
+ ],
+ },
+ "oreganno": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:oregannoUi",
+ "vars": [
+ v("hgvs", "bool", "hg/hgTrackUi/hgTrackUi.c:952",
+ note="Via labelMakeCheckBox, which is generic: the caller "
+ "picks the suffix."),
+ v("common", "bool", "hg/hgTrackUi/hgTrackUi.c:953"),
+ ],
+ "note": "Its type filters are NOT track-scoped: they use the global "
+ "names in oregannoTypeString[].",
+ },
+ "lrg": {
+ "cfgUi": "hg/lib/hui.c:lrgCfgUi",
+ "vars": [],
+ "note": "cds + indel families only.",
+ },
+ "gene ID label configs": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:geneIdConfig and friends",
+ "vars": [
+ v("label", "list", "hg/hgTrackUi/hgTrackUi.c:geneIdConfig",
+ multi=True,
+ note="Shared shape for refGene, ncbiGene, xenoRefGene, "
+ "knownGene, ensGene, ensGeneNonCoding, vegaGeneComposite, "
+ "rgdGene2, hg17Kg, refSeqComposite, omimGene, omimGene2, "
+ "omimLocation, ucscRetro*, transMapAln*. Each supplies a "
+ "different value list."),
+ ],
+ },
+ "transRegCode": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c:transRegCodeUi",
+ "vars": [],
+ "note": "Explanatory text only, no controls.",
+ },
+ "wikiTrack / quickLiftChain / hgPcrResult / cgapSage": {
+ "cfgUi": "hg/hgTrackUi/hgTrackUi.c",
+ "vars": [],
+ "note": "No cart vars of their own at UI time.",
+ },
+}
+
+# ---------------------------------------------------------------------------
+# Vars that configure exactly one track but are NOT scoped by track name.
+# These are the ones an accessor layer cannot generate from tdb->track.
+# ---------------------------------------------------------------------------
+
+GLOBAL_BUT_TRACK_SPECIFIC = [
+ v("dbRIP.genoRegion", "enum", "hg/inc/hui.h:GENO_REGION", sep="",
+ default="any", note="retroposons / dbRIP* tracks. 'dbRIP' is a "
+ "pseudo-namespace, not a track name."),
+ v("dbRIP.polySource", "enum", "hg/inc/hui.h:POLY_SOURCE", sep="",
+ default="don't care"),
+ v("dbRIP.polySubFamily", "enum", "hg/inc/hui.h:POLY_SUBFAMILY", sep="",
+ default="any"),
+ v("dbRIP.ethnicGroup", "enum", "hg/inc/hui.h:ETHNIC_GROUP", sep="",
+ default="any"),
+ v("dbRIP.ethnicExcInc", "enum", "hg/inc/hui.h:ETHNIC_GROUP_EXCINC",
+ sep="", values=["include", "exclude"]),
+ v("tfbsConsSitesCutoff", "float", "hg/inc/hui.h:TFBS_SITES_CUTOFF",
+ sep="", default="2.33", note="tfbsConsSites track."),
+ v("ucsfdemoER", "enum", "hg/inc/hui.h:UCSF_DEMO_ER", sep="",
+ default="no filter", note="CGHBreastCancerUCSF track."),
+ v("ucsfdemoPR", "enum", "hg/inc/hui.h:UCSF_DEMO_PR", sep="",
+ default="no filter"),
+ v("hapmapSnps_popCount", "enum", "hg/inc/hui.h:HAP_POP_COUNT", sep=""),
+ v("hapmapSnps_isMixed", "enum", "hg/inc/hui.h:HAP_POP_MIXED", sep=""),
+ v("hapmapSnps_monomorphic_<pop>", "bool",
+ "hg/inc/hui.h:HAP_MONO_PREFIX", sep=""),
+ v("hapmapSnps_ortho_<species>", "bool",
+ "hg/inc/hui.h:HAP_ORTHO_PREFIX", sep=""),
+ v("hapmapSnps_orthoQual_<species>", "int",
+ "hg/inc/hui.h:HAP_ORTHO_QUAL_PREFIX", sep=""),
+ v("exprssn.color", "enum", "hg/hgTrackUi/hgTrackUi.c:1287", sep="",
+ values=["rg", "rb"],
+ note="Shared by affy, affyAllExon and rosetta: one namespace, three "
+ "tracks."),
+ v("hgt.affyPhase2.tnfg", "enum", "hg/hgTrackUi/hgTrackUi.c:2409", sep="",
+ note="affyTxnPhase2 track, parked in the hgt.* namespace."),
+ v("snp125ColorSource and the snp125*OldColorVars arrays", "string",
+ "hg/cgilib/snp125Ui.c:snp125OldColorVarToNew", sep="",
+ note="Pre-<track>. spellings, still read for backward compatibility "
+ "and rewritten to the track-scoped form."),
+]
+
+# ---------------------------------------------------------------------------
+# Other CGIs that keep per-track state in the same cart. hgTracks and
+# hgTrackUi are not the only writers, so an accessor layer that lives in
+# hg/lib has to cover these too.
+# ---------------------------------------------------------------------------
+
+OTHER_CGIS = {
+ "hgc": {
+ "what": "The details page reads most of the same vars hgTracks does, "
+ "but it also owns a few of its own, and in two places it "
+ "spells a shared var differently.",
+ "vars": [
+ v("speciesOrder", "string", "hg/hgc/mafClick.c:609",
+ note="maf and rnaFold details pages; user-chosen species "
+ "order."),
+ v("vis", "enum", "hg/hgc/mafClick.c:584",
+ note="Per-species visibility on the maf details page."),
+ v("_pairEndsByName", "bool", "hg/hgc/bamClick.c:271", sep="_",
+ note="INCONSISTENCY: hui.c writes this as "
+ "<track>.pairEndsByName (dot), hgc reads it with an "
+ "underscore, so the details page does not follow the UI "
+ "setting. Worth reconciling before either form is baked "
+ "into a schema."),
+ v("_geneTrack", "list", "hg/hgc/hgc.c:19635", sep="_",
+ multi=True,
+ note="snp125-era gene tracks for functional annotation, "
+ "written by hgTrackUi.c:191. Not to be confused with the "
+ "bigDbSnp <track>.geneTrack: separate features, each "
+ "internally consistent."),
+ v("interProXref", "bool", "hg/hgc/lowelab.c:753",
+ note="Lowe lab tracks."),
+ ],
+ },
+ "hgc extended DNA": {
+ "what": "The Extended DNA page (hg/hgc/hgc.c:doGetDnaExtended1) keeps "
+ "one case/color set per track. A real per-track group that "
+ "no cfgUi function knows about.",
+ "vars": [
+ v("_case", "bool", "hg/hgc/hgc.c:5746", sep="_",
+ note="Upper case this track's bases."),
+ v("_u", "bool", "hg/hgc/hgc.c:5748", sep="_", note="Underline."),
+ v("_b", "bool", "hg/hgc/hgc.c:5750", sep="_", note="Bold."),
+ v("_i", "bool", "hg/hgc/hgc.c:5752", sep="_", note="Italic."),
+ v("_red", "int", "hg/hgc/hgc.c:5754", sep="_", note="0-255."),
+ v("_green", "int", "hg/hgc/hgc.c:5756", sep="_", note="0-255."),
+ v("_blue", "int", "hg/hgc/hgc.c:5758", sep="_", note="0-255."),
+ ],
+ },
+ "hgTables": {
+ "what": "hgTables addresses the SAME data by db and table rather than "
+ "by track, so its per-dataset state does not live under the "
+ "track name at all. This is the biggest structural mismatch "
+ "in the cart: two CGIs, two namespaces, one dataset.",
+ "vars": [
+ v("hgta_fil.v.<db>.<table>.<field>.pat", "string",
+ "hg/hgTables/filterFields.c:646", sep="",
+ note="Filter text box. Sibling types are .dd (dropdown), "
+ ".cmp (comparison), .rawQuery, .maxOutput."),
+ v("hgta_fs.check.<db>.<table>.<field>", "bool",
+ "hg/hgTables/filterFields.c:251", sep="",
+ note="Output field selection."),
+ v("hgta_subtrackMerge*", "string",
+ "hg/hgTables/hgTables.h:534", sep="",
+ note="Primary, Op, MoreThreshold, LessThreshold, WigOp, "
+ "RequireAll, UseMinScore, MinScore."),
+ v("_sel", "bool", "hg/hgTables/compositeTrack.c:67", sep="_",
+ note="The one place hgTables does use the track-scoped form: "
+ "it reads subtrack selection the same way hgTracks does."),
+ v("hgta_track, hgta_table, hgta_database", "string",
+ "hg/hgTables/hgTables.h:467", sep="",
+ note="Current selection, session-scoped rather than "
+ "per-track."),
+ ],
+ },
+}
+
+# ---------------------------------------------------------------------------
+# Track-scoped state that does NOT start with the track name. These are the
+# cases a "<trackName> at the top" hierarchy has to special-case.
+# ---------------------------------------------------------------------------
+
+EXCEPTIONS = [
+ {"pattern": "cgs_<track>_<var>",
+ "what": "chromGraph settings",
+ "src": "hg/lib/chromGraph.c:chromGraphVarName",
+ "why": "Prefix comes first, so a prefix scan for '<track>.' misses it."},
+ {"pattern": "hgtgroup_<group>_close",
+ "what": "Track group open/closed on the main page",
+ "src": "hg/hgTrackUi/hgTrackUi.c:3917",
+ "why": "Keyed by track group, not by track."},
+ {"pattern": "hapmapSnps_monomorphic_<pop>, hapmapSnps_ortho_<species>, "
+ "hapmapSnps_orthoQual_<species>",
+ "what": "HapMap SNP filters",
+ "src": "hg/hgTrackUi/hgTrackUi.c:2608",
+ "why": "Shared across the whole hapmapSnps track set, keyed by "
+ "population/species rather than by track."},
+ {"pattern": "complement_<db>, hgt.baseTitle_<db>",
+ "what": "Base Position ruler options",
+ "src": "hg/hgTrackUi/hgTrackUi.c:2155",
+ "why": "Assembly-scoped, not track-scoped, even though they are edited "
+ "from the ruler's config page."},
+ {"pattern": "dup_tracks",
+ "what": "List of duplicated tracks",
+ "src": "hg/inc/dupTrack.h:DUP_TRACKS_VAR",
+ "why": "Points at a trash file that defines the dup_<n>_<track> "
+ "namespaces."},
+ {"pattern": "<track>.sha1, multiRegionBedPadding, virtWinFull",
+ "what": "Multi-region state",
+ "src": "hg/inc/hui.h:176",
+ "why": "Mixed: the sha1 is track-scoped but the rest is session-scoped."},
+ {"pattern": "hgt.oligoMatch, hgt.cutters, hgt.gcOnFly, hgt.motifs",
+ "what": "Settings for the synthetic tracks (Short Match, Restriction "
+ "Enzymes, GC on the fly, ruler motifs)",
+ "src": "hg/inc/hui.h:83-127",
+ "why": "These tracks store their state in the hgt.* CGI namespace "
+ "rather than under their own track name."},
+ {"pattern": "<varPrefix>_facet_*, <varPrefix>_order, <varPrefix>_page",
+ "what": "Faceted table and sortable table state",
+ "src": "hg/lib/facetedTable.c, hg/lib/tablesTables.c",
+ "why": "varPrefix is usually but not always the track name."},
+ {"pattern": "hgt_<track>_filterType, hgt_<track>_filterPmId",
+ "what": "Database of Genomic Variants filters",
+ "src": "hg/hgTrackUi/hgTrackUi.c:dgvUi",
+ "why": "Track name sits in the middle of the name, so neither a "
+ "'<track>.' prefix scan nor a suffix scan finds it."},
+ {"pattern": "<track>.<view>.<var>",
+ "what": "A composite view",
+ "src": "hg/lib/cart.c:cartLookUpVariableClosestToHome",
+ "why": "Not really an exception, but worth stating: the middle "
+ "component is a view name, so a two-component parse of "
+ "'<track>.<var>' is wrong for composites."},
+]
+
+# ---------------------------------------------------------------------------
+# assemble
+# ---------------------------------------------------------------------------
+
+def build():
+ return {
+ "ticket": 37838,
+ "what": "Track-scoped cart variables, arranged as the hierarchy a "
+ "JSON cart and a cart accessor layer would use.",
+ "naming": NAMING,
+ "levels": {
+ "1_trackName": {
+ "what": "Top of the hierarchy. Every variable below is "
+ "scoped by one track name (or by a composite/view "
+ "above that track).",
+ "prefixes": NAMING["trackNamePrefixes"],
+ },
+ "2_common": {
+ "what": "Applies to a track of any type.",
+ "groups": COMMON,
+ },
+ "2b_container": {
+ "what": "Applies to a track that contains other tracks.",
+ "groups": CONTAINER,
+ },
+ "3_byType": {
+ "what": "Keyed by eCfgType (hg/inc/trackDb.h:439) where one "
+ "exists, otherwise by the type or track-name special "
+ "case that supplies the UI.",
+ "types": TYPES,
+ },
+ "3b_byTrackName": {
+ "what": "Tracks whose vars are hard-coded literals rather "
+ "than composed from tdb->track. Same <track>.<var> "
+ "shape, but invisible to a search for the suffix.",
+ "tracks": BY_TRACK_NAME,
+ },
+ "4_families": {
+ "what": "Leaf groups shared by several types. A type "
+ "references these instead of repeating them; several "
+ "are themselves keyed by field or by name, which is "
+ "where the hierarchy goes one level deeper.",
+ "groups": FAMILIES,
+ },
+ },
+ "otherCgis": {
+ "what": "CGIs other than hgTracks/hgTrackUi that keep per-track "
+ "or per-dataset state in the same cart.",
+ "groups": OTHER_CGIS,
+ },
+ "notScopedByTrackName": {
+ "what": "Configures one track, but the name has no track "
+ "component, so an accessor keyed on tdb->track cannot "
+ "reach it.",
+ "vars": GLOBAL_BUT_TRACK_SPECIFIC,
+ },
+ "exceptions": EXCEPTIONS,
+ }
+
+
+def counts(cat):
+ n_common = sum(len(g["vars"]) for g in COMMON.values())
+ n_cont = sum(len(g["vars"]) for g in CONTAINER.values())
+ n_fam = sum(len(g["vars"]) for g in FAMILIES.values())
+ n_type = sum(len(t["vars"]) for t in TYPES.values())
+ n_name = sum(len(t["vars"]) for t in BY_TRACK_NAME.values())
+ n_glob = len(GLOBAL_BUT_TRACK_SPECIFIC)
+ n_cgi = sum(len(g["vars"]) for g in OTHER_CGIS.values())
+ return {
+ "common": n_common,
+ "container": n_cont,
+ "families": n_fam,
+ "types": n_type,
+ "byTrackName": n_name,
+ "notScopedByTrack": n_glob,
+ "otherCgis": n_cgi,
+ "typeCount": len(TYPES),
+ "total": (n_common + n_cont + n_fam + n_type + n_name + n_glob
+ + n_cgi),
+ }
+
+
+# ---------------------------------------------------------------------------
+# HTML rendering
+# ---------------------------------------------------------------------------
+
+CSS = """
+body { font: 14px/1.5 -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
+ margin: 0; color: #12191f; background: #fff; }
+header { background: #14385c; color: #fff; padding: 18px 28px; }
+header h1 { margin: 0 0 4px; font-size: 20px; font-weight: 600; }
+header p { margin: 0; font-size: 13px; color: #c5d6e8; }
+main { max-width: 1080px; margin: 0 auto; padding: 22px 28px 60px; }
+h2 { font-size: 17px; margin: 30px 0 6px; padding-bottom: 5px;
+ border-bottom: 2px solid #14385c; }
+h3 { font-size: 15px; margin: 20px 0 4px; color: #14385c; }
+p.what { margin: 4px 0 10px; color: #4a5764; font-size: 13px;
+ max-width: 78ch; }
+table { border-collapse: collapse; width: 100%; margin: 6px 0 14px;
+ font-size: 13px; }
+th { text-align: left; background: #eef2f6; padding: 5px 8px;
+ border-bottom: 1px solid #c9d3dd; font-weight: 600; }
+td { padding: 5px 8px; border-bottom: 1px solid #eceff2;
+ vertical-align: top; }
+tr:hover td { background: #f7fafd; }
+code, .n { font-family: ui-monospace, Menlo, Consolas, monospace;
+ font-size: 12.5px; }
+.n { font-weight: 600; color: #0b3d62; white-space: nowrap; }
+.t { color: #7a3ba8; white-space: nowrap; }
+.src { color: #6b7885; font-size: 11.5px; white-space: nowrap; }
+.note { color: #4a5764; font-size: 12.5px; }
+.vals { color: #276749; font-size: 12px; }
+.legacy { background: #fff8e1; }
+.pill { display: inline-block; background: #e8eef5; color: #14385c;
+ border-radius: 9px; padding: 1px 8px; font-size: 11.5px;
+ margin-right: 5px; }
+.tree { font-family: ui-monospace, Menlo, Consolas, monospace;
+ font-size: 12.5px; background: #f7fafd; border: 1px solid #dde5ec;
+ padding: 12px 14px; white-space: pre; overflow-x: auto; }
+#filter { width: 320px; padding: 6px 9px; font-size: 13px;
+ border: 1px solid #b9c4cf; border-radius: 4px; margin: 10px 0; }
+.hidden { display: none; }
+.count { color: #6b7885; font-weight: 400; font-size: 13px; }
+"""
+
+TREE = """<track> visibility (bare name)
+ |
+ +- common to any track ................. _sel _imgOrd _hideKids
+ | priority group heightPer
+ | colorOverride[On]
+ | nameFilter doWiggle doMergeItems
+ | section_<section>_close
+ |
+ +- container layer ..................... composite: displaySubtracks,
+ | hideEmptySubtracks, sortOrder,
+ | filterComp.<groupTag>
+ | view: <view>.<anyTypeVar>
+ | multiWig: aggregate, viewFunc
+ |
+ +- type layer (eCfgType) ............... wig | bedScore | bedFilt | peak |
+ | genePred | psl | chain | net |
+ | wigMaf | bam | vcf | snake | long |
+ | interact | hic | barChart | lolly |
+ | bigDbSnp | bigRmsk (+ non-eCfgType:
+ | gtex, expRatio, sample, chromGraph,
+ | factorSource, ld, gvf, snp125,
+ | blast, pubs, transMap, mrna)
+ |
+ +- by track name (literal vars) ........ stsMap.filter cghNci60.color
+ | switchDbTss.pseudo rosetta.et ...
+ |
+ +- leaf groups (shared, and nested) .... filter.<field>[Min|Max]
+ filterBy.<field> (list)
+ filterText.<field>
+ filterType.<field>
+ highlight*.<field> (twins)
+ cds: baseColorDrawOpt, codonNumbering
+ label: label, label.<kind>
+ decorator.<name>.<var> <- nested
+ <species> (wigMaf)
+ <attribute><Value> (snp125 color)
+
+other writers of the same cart:
+ hgc ................................... <track>.speciesOrder <track>.vis
+ <track>_case/_u/_b/_i/_red/_green/_blue
+ hgTables .............................. hgta_fil.v.<db>.<table>.<field>.<type>
+ hgta_fs.check.<db>.<table>.<field>
+ (addresses data by db.table, NOT by
+ track - the big mismatch)
+"""
+
+
+def esc(s):
+ return html.escape(str(s), quote=False)
+
+
+def var_rows(vars_, prefix=None):
+ """prefix replaces the generic <track> stand-in, for the by-track-name
+ section where the real track name is part of the literal var name."""
+ stand_in = esc(prefix) if prefix else "<track>"
+ out = []
+ for e in vars_:
+ sep = e.get("sep", ".")
+ name = e["name"]
+ if sep == "":
+ # empty name = the bare track name (visibility); otherwise the
+ # var has an absolute name with no track component at all
+ full = stand_in if not name else esc(name)
+ elif sep in (".", "_"):
+ # legacy entries already carry their leading underscore
+ joiner = "" if name.startswith(sep) else sep
+ full = stand_in + esc(joiner) + esc(name)
+ else:
+ full = esc(sep) + esc(name)
+ cls = ' class="legacy"' if sep == "_" else ""
+ bits = []
+ if e.get("multi"):
+ bits.append('<span class="pill">multi</span>')
+ if e.get("values"):
+ bits.append('<span class="vals">' +
+ esc(" | ".join(e["values"])) + "</span>")
+ if e.get("default") is not None:
+ bits.append('<span class="note">default ' +
+ esc(e["default"]) + "</span>")
+ if e.get("tdbDefault"):
+ bits.append('<span class="note">trackDb: ' +
+ esc(e["tdbDefault"]) + "</span>")
+ if e.get("note"):
+ bits.append('<span class="note">' + esc(e["note"]) + "</span>")
+ out.append(
+ "<tr%s><td class='n'>%s</td><td class='t'>%s</td>"
+ "<td>%s</td><td class='src'>%s</td></tr>"
+ % (cls, full, esc(e["type"]), " ".join(bits), esc(e["src"])))
+ return "\n".join(out)
+
+
+def table(vars_, prefix=None):
+ if not vars_:
+ return "<p class='note'>No vars of its own; see the leaf groups it "\
+ "pulls in.</p>"
+ return ("<table><tr><th>variable</th><th>type</th><th>values / notes</th>"
+ "<th>read at</th></tr>%s</table>" % var_rows(vars_, prefix))
+
+
+def render_html(cat):
+ c = counts(cat)
+ p = []
+ p.append("<title>Track cart variables (#37838)</title>")
+ p.append("<style>%s</style>" % CSS)
+ p.append("<header><h1>Track-scoped cart variables</h1>"
+ "<p>Refs #37838 — arranged as the hierarchy a JSON cart "
+ "and a cart accessor layer would use. %d variables across %d "
+ "track types.</p></header>" % (c["total"], c["typeCount"]))
+ p.append("<main>")
+
+ p.append("<h2>The shape</h2>")
+ p.append("<div class='tree'>%s</div>" % esc(TREE))
+
+ p.append("<h2>How a name is built</h2>")
+ n = cat["naming"]
+ p.append("<p class='what'>Canonical form <code>%s</code>. Legacy form "
+ "<code>%s</code> (highlighted in yellow below). %s</p>"
+ % (esc(n["canonical"]), esc(n["legacy"]), esc(n["legacyNote"])))
+ p.append("<p class='what'><b>Lookup order</b> (%s): %s. %s</p>"
+ % (esc(n["lookupOrderSrc"]),
+ " → ".join("<code>%s</code>" % esc(x)
+ for x in n["lookupOrder"]),
+ esc(n["lookupOrderNote"])))
+ p.append("<p class='what'><b>Values.</b> %s</p>"
+ % esc(n["valueEncoding"]))
+ p.append("<p class='what'><b>Track name prefixes.</b> %s</p>"
+ % ", ".join("<code>%s</code> (%s)" % (esc(x["prefix"]),
+ esc(x["what"]))
+ for x in n["trackNamePrefixes"]))
+
+ p.append("<input id='filter' placeholder='filter variables...'>")
+
+ p.append("<h2>Level 2 — common to any track "
+ "<span class='count'>(%d)</span></h2>" % c["common"])
+ for k, g in COMMON.items():
+ p.append("<h3>%s</h3><p class='what'>%s</p>%s"
+ % (esc(k), esc(g["what"]), table(g["vars"])))
+
+ p.append("<h2>Level 2b — containers "
+ "<span class='count'>(%d)</span></h2>" % c["container"])
+ for k, g in CONTAINER.items():
+ p.append("<h3>%s</h3><p class='what'>%s</p>%s"
+ % (esc(k), esc(g["what"]), table(g["vars"])))
+
+ p.append("<h2>Level 3 — by track type "
+ "<span class='count'>(%d in %d types)</span></h2>"
+ % (c["types"], c["typeCount"]))
+ for k, t in TYPES.items():
+ p.append("<h3>%s</h3>" % esc(k))
+ meta = ["<span class='pill'>%s</span>" % esc(t["cfgType"])]
+ meta.append("<span class='note'>tdb type: %s</span>"
+ % esc(", ".join(t["tdbTypes"])))
+ p.append("<p class='what'>%s<br><span class='src'>%s</span>%s</p>"
+ % (" ".join(meta), esc(t["cfgUi"]),
+ ("<br><span class='note'>%s</span>" % esc(t["note"]))
+ if t.get("note") else ""))
+ if t.get("families"):
+ p.append("<p class='what'><b>Also uses:</b> %s</p>"
+ % ", ".join("<code>%s</code>" % esc(f)
+ for f in t["families"]))
+ p.append(table(t["vars"]))
+ if t.get("tdbOnly"):
+ p.append("<p class='what'><b>trackDb only</b> (no cart var, but "
+ "supplies defaults): %s</p>"
+ % ", ".join("<code>%s</code>" % esc(x)
+ for x in t["tdbOnly"]))
+
+ p.append("<h2>Level 3b — by track name "
+ "<span class='count'>(%d)</span></h2>" % c["byTrackName"])
+ p.append("<p class='what'>These write their variables as literals "
+ "(<code>\"stsMap.filter\"</code>) instead of composing them from "
+ "<code>tdb->track</code>. Same shape, but a suffix search "
+ "will not find them, which is why they are easy to miss in a "
+ "rewrite.</p>")
+ for k, t in BY_TRACK_NAME.items():
+ p.append("<h3>%s</h3><p class='what'><span class='src'>%s</span>%s</p>"
+ % (esc(k), esc(t["cfgUi"]),
+ ("<br><span class='note'>%s</span>" % esc(t["note"]))
+ if t.get("note") else ""))
+ # use the real track name in the rendered var when the key is a
+ # single track rather than a group of them
+ pfx = k if re.fullmatch(r"[A-Za-z0-9_]+", k) else None
+ p.append(table(t["vars"], pfx))
+
+ p.append("<h2>Not scoped by track name "
+ "<span class='count'>(%d)</span></h2>" % c["notScopedByTrack"])
+ p.append("<p class='what'>Each of these configures exactly one track (or "
+ "one small family of tracks) but carries no track component in "
+ "its name, so an accessor keyed on <code>tdb->track</code> "
+ "cannot reach it and a JSON cart cannot file it under the "
+ "track. They need either a rename or an explicit alias "
+ "table.</p>")
+ p.append(table(GLOBAL_BUT_TRACK_SPECIFIC))
+
+ p.append("<h2>Level 4 — shared leaf groups "
+ "<span class='count'>(%d)</span></h2>" % c["families"])
+ for k, g in FAMILIES.items():
+ p.append("<h3>%s</h3><p class='what'>%s</p>%s"
+ % (esc(k), esc(g["what"]), table(g["vars"])))
+
+ p.append("<h2>Other CGIs "
+ "<span class='count'>(%d)</span></h2>" % c["otherCgis"])
+ p.append("<p class='what'>hgTracks and hgTrackUi are not the only writers "
+ "of per-track cart state, so an accessor layer in hg/lib has to "
+ "account for these as well.</p>")
+ for k, g in OTHER_CGIS.items():
+ p.append("<h3>%s</h3><p class='what'>%s</p>%s"
+ % (esc(k), esc(g["what"]), table(g["vars"])))
+
+ p.append("<h2>Exceptions — track state not under the track name</h2>")
+ p.append("<p class='what'>These are the cases that break a strict "
+ "<code><track>.<var></code> hierarchy, so any "
+ "accessor layer or JSON schema has to handle them "
+ "deliberately.</p>")
+ p.append("<table><tr><th>pattern</th><th>what</th><th>why it is "
+ "awkward</th><th>src</th></tr>")
+ for e in EXCEPTIONS:
+ p.append("<tr><td class='n'>%s</td><td>%s</td>"
+ "<td class='note'>%s</td><td class='src'>%s</td></tr>"
+ % (esc(e["pattern"]), esc(e["what"]), esc(e["why"]),
+ esc(e["src"])))
+ p.append("</table>")
+
+ p.append("</main>")
+ p.append("""<script>
+document.getElementById('filter').addEventListener('input', function() {
+ var q = this.value.toLowerCase();
+ document.querySelectorAll('table tr').forEach(function(tr) {
+ if (tr.querySelector('th')) return;
+ tr.classList.toggle('hidden', q && tr.textContent.toLowerCase().indexOf(q) < 0);
+ });
+});
+</script>""")
+ return "\n".join(p)
+
+
+def main():
+ ap = argparse.ArgumentParser(description=__doc__)
+ ap.add_argument("--json")
+ ap.add_argument("--html")
+ ap.add_argument("--check", action="store_true")
+ args = ap.parse_args()
+ cat = build()
+ if args.json:
+ with open(args.json, "w") as f:
+ json.dump(cat, f, indent=1)
+ print("wrote %s" % args.json)
+ if args.html:
+ with open(args.html, "w") as f:
+ f.write(render_html(cat))
+ print("wrote %s" % args.html)
+ if args.check or not (args.json or args.html):
+ c = counts(cat)
+ for k in sorted(c):
+ print("%-12s %s" % (k, c[k]))
+ # every family referenced by a type must exist
+ bad = 0
+ for name, t in TYPES.items():
+ for fam in t.get("families", []):
+ key = fam.split(" ")[0]
+ if key not in FAMILIES and key not in TYPES:
+ print("unknown family %r referenced by type %r"
+ % (fam, name), file=sys.stderr)
+ bad += 1
+ if bad:
+ return 1
+ print("families ok")
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())