78988553dd9b460c26f0b9f21f15a1aacfad9dab lrnassar Fri Aug 21 15:44:40 2026 -0700 Polish pass on the mouseDevTimecourse tracks after a Playwright QA sweep. refs #37001 Sentence-case the tissue names and the facet column titles, so the barChart facet filter reads "Tissue / Spleen" rather than "tissue / spleen" and the bigWig matrix reads "Spleen". Only the first character is upper-cased. Added sentenceCaseTissues.sh, which does the .facets and .categories files and is idempotent, since the hub still ships lower-case and this has to be replayed after any refetch. The count and color column names are deliberately left lower-case: barChartUi.c requires a field literally named "count" to load the file at all, and facetedTable.c keys its merge logic on "count", "color" and "val". Renaming the faceted columns means trackDb matches, so the stanzas now read barChartFacets Tissue,Timepoint. Set priority on the container children so the default-visible M21 TPM sorts first and the signal composite sorts last. The composite needs an explicit value; without one it inherits the superTrack's 0.6 and floats to the top. Fix the All reads view, which was inert. Every all-reads subtrack shipped parent off, so switching the view to full revealed nothing. The view's own visibility already gates drawing, so the subtrack state should not encode the view as well. The default image is unchanged at 78 unique-reads rep1 tracks, and switching the view to full now yields 156. This also makes the Rep 2 toggle symmetric across the two views. Rename the bigWig subGroup3 display label from Age to Timepoint, matching the barChart facet and the .facets column. The group name stays "age" because dimensions and sortOrder reference it by name. Add relatedTracks cross-links between the mm10 container and Tabula Muris. Not Tabula Muris Senis, which is not on the RR. Description pages: reorder the mm10 subtrack list to match the new display order, "sub tracks" to "subtracks", capitalise the colour legend tissue names, and correct the mm39 Il11ra2 note - the gene appears three times, two of them stacked at one position and sharing a details page, with the third 497 kb away. Makedocs record the casing step, its ordering constraint relative to the reorder and colour steps, and the count/color naming constraint. diff --git src/hg/makeDb/scripts/mouseDevTimecourse/generateBigwigTrackDb.py src/hg/makeDb/scripts/mouseDevTimecourse/generateBigwigTrackDb.py index cee34b025a5..ce1fe21a468 100755 --- src/hg/makeDb/scripts/mouseDevTimecourse/generateBigwigTrackDb.py +++ src/hg/makeDb/scripts/mouseDevTimecourse/generateBigwigTrackDb.py @@ -87,30 +87,36 @@ def tissue_short(name): return TISSUE_SHORT.get(name, name) def tissue_key(name): return name.replace(' ', '_') def tissue_tag(name): """subGroup tag carrying the biological sort order, e.g. t14_forebrain.""" return 't%02d_%s' % (TISSUE_ORDER.index(name) + 1, tissue_key(name)) +def tissue_label(name): + """Sentence-cased subGroup label; trackDb renders the underscores as spaces.""" + key = tissue_key(name) + return key[:1].upper() + key[1:] + + def age_label(life_stage, age): if life_stage == 'embryonic': return 'e' + str(age) if life_stage == 'postnatal': if float(age) == 0: return 'P0' return 'P' + str(age) return life_stage + '_' + str(age) def age_key(life_stage, age): return age_label(life_stage, age).replace('.', '_') def accession(url): @@ -120,31 +126,33 @@ def hex_to_rgb(h): h = h.lstrip('#') return ','.join(str(int(h[i:i + 2], 16)) for i in (0, 2, 4)) def load_colors(): """Build a (tissue, timepoint_label) -> hex color map from the .facets file.""" colors = {} with open(FACETS) as f: f.readline() for line in f: cols = line.rstrip('\n').split('\t') if len(cols) < 5: continue tissue, timepoint, hex_color = cols[2], cols[3], cols[4] - colors[(tissue, timepoint)] = hex_color + # Keyed lower-case: the .facets tissue is sentence-cased for display + # but the biosample TSV supplies it lower-case. + colors[(tissue.lower(), timepoint)] = hex_color return colors def load_replicates(): """Build a file accession -> ENCODE biological replicate number map.""" reps = {} with open(REPLICATES) as f: f.readline() for line in f: line = line.rstrip('\n') if not line: continue acc, rep = line.split('\t') reps[acc] = int(rep) return reps @@ -166,44 +174,50 @@ rows.append(dict(zip(header, line.split('\t')))) unknown = sorted({t for t in (r['biosample_term_name'] for r in rows) if t not in TISSUE_ORDER}) if unknown: sys.exit('tissue missing from TISSUE_ORDER: %s' % ', '.join(unknown)) ages = sorted( {(row['mouse_life_stage'], row['age']) for row in rows}, key=lambda p: (p[0], float(p[1])), ) # Composite parent stanza print(' track developmentTimecourseSignalMm10') print(' parent mouseDevTimecourse') + # Sorts after the four bigBarChart siblings, which take 1-4. Without an + # explicit value this inherits the superTrack's 0.6 and floats to the top. + print(' priority 5') print(' compositeTrack on') print(' type bigWig') print(' shortLabel Timecourse Signal') print(' longLabel ENCODE mouse development time course bulk RNA-seq signal') print(' visibility hide') print(' group regulation') print(' html developmentTimecourseSignalMm10') print(' subGroup1 view Views unique=Unique_reads all=All_reads') - tissue_grp = ' '.join(tissue_tag(t) + '=' + tissue_key(t) for t in TISSUE_ORDER) + tissue_grp = ' '.join(tissue_tag(t) + '=' + tissue_label(t) for t in TISSUE_ORDER) print(' subGroup2 tissue Tissue ' + tissue_grp) age_grp = ' '.join(age_key(ls, age) + '=' + age_label(ls, age) for ls, age in ages) - print(' subGroup3 age Age ' + age_grp) + # Display label is Timepoint, matching the bigBarChart facet filter and the + # .facets column. The group name stays 'age' because dimensions and sortOrder + # reference it by name. + print(' subGroup3 age Timepoint ' + age_grp) print(' subGroup4 rep Replicate rep1=Rep_1 rep2=Rep_2') print(' dimensions dimX=age dimY=tissue dimA=rep') print(' dimensionAchecked rep1') print(' sortOrder view=+ tissue=+ age=+ rep=+') print(' dragAndDrop subTracks') print(' noInherit on') print() views = ( ('unique', 'Unique', 'Unique reads', 'signal_of_unique_reads', 'full'), ('all', 'All', 'All reads', 'signal_of_all_reads', 'hide'), ) for view_key, view_cap, view_label, url_col, view_visibility in views: @@ -225,41 +239,44 @@ t_tag = tissue_tag(tissue) a_key = age_key(ls, age) a_lbl = age_label(ls, age) t_short = tissue_short(tissue) url = row[url_col] acc = accession(url) big_data_url = '/gbdb/mm10/mouseDevTimecourse/' + acc + '.bigWig' if acc not in replicates: sys.exit('%s has no replicate number in %s; rerun ' 'fetchReplicateNumbers.py' % (acc, REPLICATES)) rep_num = replicates[acc] - hex_color = colors.get((tissue, a_lbl)) + hex_color = colors.get((tissue.lower(), a_lbl)) if hex_color is None: sys.exit('no color in %s for (%s, %s)' % (FACETS, tissue, a_lbl)) rgb = hex_to_rgb(hex_color) track = 'developmentTimecourseSignalMm10_' + acc - # Default on for rep1 + unique-reads (78 subtracks visible when the - # composite is enabled). rep2 and all-reads remain off; users can - # enable them from the trackUi page. - parent_state = 'on' if (rep_num == 1 and view_key == 'unique') else 'off' + # Check rep1 in both views, and leave rep2 unchecked. Whether the + # all-reads subtracks actually draw is controlled by their view's + # visibility, which is 'hide'; so the default image is unchanged at 78 + # unique-reads rep1 tracks. Encoding the view here as well would leave + # the All reads view with nothing checked, and switching it to full + # would then appear to do nothing. + parent_state = 'on' if rep_num == 1 else 'off' # Title Case on the tissue and the replicate marker; e14.5 / P0 stay # as written since they are standard developmental stage notation. short = (t_short.capitalize() + ' ' + a_lbl + ' R' + str(rep_num) + ' ' + VIEW_CODE[view_key]) if len(short) > MAX_SHORT_LABEL: sys.exit('shortLabel %d chars, limit %d: %s' % (len(short), MAX_SHORT_LABEL, short)) clipped = short[:LEFT_LABEL_WIDTH] if clipped in seen_labels and seen_labels[clipped] != short: sys.exit('shortLabels "%s" and "%s" are identical in the first %d ' 'characters, so hgTracks draws them the same. Shorten the ' 'tissue abbreviation in TISSUE_SHORT.' % (seen_labels[clipped], short, LEFT_LABEL_WIDTH)) seen_labels[clipped] = short