@datagrok/proteomics 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +52 -3
  2. package/CLAUDE.md +178 -0
  3. package/README.md +195 -3
  4. package/detectors.js +152 -9
  5. package/dist/package-test.js +1 -1744
  6. package/dist/package-test.js.map +1 -1
  7. package/dist/package.js +1 -146
  8. package/dist/package.js.map +1 -1
  9. package/docs/personas-and-capabilities.md +165 -0
  10. package/files/demo/README.md +264 -0
  11. package/files/demo/cptac-spike-in.txt +1571 -0
  12. package/files/demo/enrichment-demo.csv +120 -0
  13. package/files/demo/fragpipe-smoke-test.tsv +11 -0
  14. package/files/demo/proteinGroups.txt +28 -0
  15. package/files/demo/spectronaut-hye-candidates.tsv +94 -0
  16. package/files/demo/spectronaut-hye-demo.tsv +8761 -0
  17. package/files/demo/spectronaut-hye-mix.tsv +8761 -0
  18. package/files/demo/spectronaut-hye-precursor-golden.json +938 -0
  19. package/files/demo/spectronaut-hye-precursor-golden.tsv +235 -0
  20. package/files/demo/spectronaut-hye-precursor.tsv +493 -0
  21. package/images/enrichment-crosslink.png +0 -0
  22. package/images/enrichment-term-selected.png +0 -0
  23. package/images/hero.png +0 -0
  24. package/images/pipeline.svg +80 -0
  25. package/package.json +87 -62
  26. package/scripts/deqms_de.R +60 -0
  27. package/scripts/limma_de.R +42 -0
  28. package/scripts/vsn_normalize.R +19 -0
  29. package/src/analysis/differential-expression.ts +450 -0
  30. package/src/analysis/enrichment-export.ts +101 -0
  31. package/src/analysis/enrichment.ts +602 -0
  32. package/src/analysis/experiment-setup.ts +199 -0
  33. package/src/analysis/imputation.ts +407 -0
  34. package/src/analysis/log2-scale.ts +139 -0
  35. package/src/analysis/normalization.ts +255 -0
  36. package/src/analysis/pca.ts +254 -0
  37. package/src/analysis/spc-storage.ts +515 -0
  38. package/src/analysis/spc.ts +544 -0
  39. package/src/analysis/subcellular-location.ts +431 -0
  40. package/src/demo/enrichment-demo.ts +94 -0
  41. package/src/demo/proteomics-demo.ts +123 -0
  42. package/src/global.d.ts +15 -0
  43. package/src/menu.ts +133 -0
  44. package/src/package-api.ts +136 -14
  45. package/src/package-test.ts +45 -20
  46. package/src/package.g.ts +161 -0
  47. package/src/package.ts +1029 -17
  48. package/src/panels/protein-focus.ts +63 -0
  49. package/src/panels/published-analysis-panel.ts +151 -0
  50. package/src/panels/uniprot-panel.ts +349 -0
  51. package/src/parsers/fragpipe-parser.ts +200 -0
  52. package/src/parsers/generic-parser.ts +197 -0
  53. package/src/parsers/maxquant-parser.ts +162 -0
  54. package/src/parsers/shared-utils.ts +163 -0
  55. package/src/parsers/spectronaut-candidates-parser.ts +307 -0
  56. package/src/parsers/spectronaut-parser.ts +604 -0
  57. package/src/publishing/assert-published-shape.ts +260 -0
  58. package/src/publishing/post-open-recovery.ts +104 -0
  59. package/src/publishing/publish-project.ts +515 -0
  60. package/src/publishing/publish-settings.ts +59 -0
  61. package/src/publishing/publish-state.ts +316 -0
  62. package/src/publishing/share-dialog.ts +171 -0
  63. package/src/publishing/trim-dataframe.ts +247 -0
  64. package/src/tests/analysis.ts +658 -0
  65. package/src/tests/enrichment-export.ts +61 -0
  66. package/src/tests/enrichment-visualization.ts +340 -0
  67. package/src/tests/enrichment.ts +224 -0
  68. package/src/tests/fragpipe-e2e.ts +74 -0
  69. package/src/tests/fragpipe-parser.ts +147 -0
  70. package/src/tests/gene-label-resolver.ts +387 -0
  71. package/src/tests/generic-parser.ts +152 -0
  72. package/src/tests/group-mean-correlation.ts +139 -0
  73. package/src/tests/log2-scale.ts +93 -0
  74. package/src/tests/organisms.ts +56 -0
  75. package/src/tests/parsers.ts +182 -0
  76. package/src/tests/publish-roundtrip.ts +584 -0
  77. package/src/tests/publish-spike.ts +377 -0
  78. package/src/tests/qc-dashboard.ts +210 -0
  79. package/src/tests/smart-pathway-filter.ts +193 -0
  80. package/src/tests/spc-formula-lines-spike.ts +129 -0
  81. package/src/tests/spc.ts +640 -0
  82. package/src/tests/spectronaut-candidates-e2e.ts +140 -0
  83. package/src/tests/spectronaut-candidates-parser.ts +398 -0
  84. package/src/tests/spectronaut-parser.ts +668 -0
  85. package/src/tests/subcellular-location.ts +361 -0
  86. package/src/tests/uniprot-panel.ts +202 -0
  87. package/src/tests/volcano.ts +603 -0
  88. package/src/utils/column-detection.ts +28 -0
  89. package/src/utils/gene-label-resolver.ts +443 -0
  90. package/src/utils/organisms.ts +82 -0
  91. package/src/utils/proteomics-types.ts +30 -0
  92. package/src/viewers/enrichment-viewers.ts +274 -0
  93. package/src/viewers/group-mean-correlation.ts +218 -0
  94. package/src/viewers/heatmap.ts +168 -0
  95. package/src/viewers/pca-plot.ts +169 -0
  96. package/src/viewers/qc-computations.ts +266 -0
  97. package/src/viewers/qc-dashboard.ts +176 -0
  98. package/src/viewers/spc-dashboard.ts +755 -0
  99. package/src/viewers/volcano.ts +690 -0
  100. package/test-console-output-1.log +2055 -0
  101. package/test-record-1.mp4 +0 -0
  102. package/tools/derive-precursor-golden-sidecar.mjs +81 -0
  103. package/tools/generate-enrichment-fixture.sh +160 -0
  104. package/tools/generate-spectronaut-candidates-fixture.mjs +212 -0
  105. package/tools/generate-spectronaut-precursor-fixture.mjs +128 -0
  106. package/tools/spectronaut-aggregate.sh +46 -0
  107. package/tools/spectronaut-aggregate.sql +80 -0
  108. package/tsconfig.json +18 -71
  109. package/webpack.config.js +86 -45
  110. package/.eslintignore +0 -1
  111. package/.eslintrc.json +0 -56
  112. package/LICENSE +0 -674
  113. package/package.png +0 -0
  114. package/scripts/number_antibody.py +0 -190
  115. package/scripts/number_antibody_abnumber.py +0 -177
  116. package/scripts/number_antibody_anarci.py +0 -200
@@ -0,0 +1,165 @@
1
+ # Personas & capabilities
2
+
3
+ Who does what with a Proteomics dataset, what each persona is *allowed* to do, and
4
+ **how that boundary is enforced** — today and where we are taking it.
5
+
6
+ This doc is the reference behind the README's ["What you can achieve"](../README.md#what-you-can-achieve)
7
+ section. The README leads with outcomes; this leads with the capability boundary and its
8
+ enforcement, because a client requirement (see [Target state](#target-state)) needs that
9
+ boundary to be real, not conventional.
10
+
11
+ ## The two personas
12
+
13
+ | Persona | Role | Outcome they want |
14
+ |---|---|---|
15
+ | **Proteomics analyst** (data generator) | Builds the analysis: import → annotate → normalize → impute → differential expression | A defensible, reproducible, FDR-controlled result they can stand behind and hand off |
16
+ | **Biology scientist** (data consumer / reviewer) | Interprets a finished analysis: volcano, enrichment, per-protein annotation | To understand *what changed and what it means* — without touching (or being able to change) the analysis itself |
17
+
18
+ The dividing line is **"the interpretation"** — the set of decisions that determine what the
19
+ result *says*: group assignment, normalization, imputation, the DE method, and the
20
+ significance thresholds. The analyst owns these. The biologist reads the consequences and
21
+ explores them, but must not alter them.
22
+
23
+ ## Capability matrix
24
+
25
+ Legend: ✅ allowed · 🚫 must not · 👁 read-only interaction (view/filter/select, no state change)
26
+
27
+ | Capability | Analyst | Biologist | Changes the interpretation? |
28
+ |---|---|---|---|
29
+ | Import a search-engine file | ✅ | — (receives a shared snapshot instead) | Produces it |
30
+ | Annotate Experiment (assign groups) | ✅ | 🚫 | **Yes** |
31
+ | Set Log2 Scale | ✅ | 🚫 | **Yes** |
32
+ | Normalize | ✅ | 🚫 | **Yes** |
33
+ | Impute Missing Values | ✅ | 🚫 | **Yes** |
34
+ | Differential Expression | ✅ | 🚫 | **Yes** |
35
+ | Compute SPC Status | ✅ | 🚫 | **Yes** |
36
+ | Volcano Plot | ✅ | 👁 | No (view) |
37
+ | Heatmap / PCA / Group-Mean Correlation / QC Dashboard | ✅ | 👁 | No (view) |
38
+ | Enrichment Analysis & Charts | ✅ | ✅ (derives biology; non-destructive) | No |
39
+ | UniProt protein panel | ✅ | ✅ | No |
40
+ | Filter / select / cross-link in any viewer | ✅ | ✅ | No |
41
+ | Share Analysis for Review | ✅ | 🚫 | N/A (publishes) |
42
+ | Save changes to a shared snapshot | ✅ (own copy) | 🚫 | **Yes** |
43
+
44
+ The 🚫 rows are the ones CK cares about: a biologist must not be able to re-run the pipeline
45
+ or re-thresholds and thereby produce a *different* interpretation of the same data.
46
+
47
+ ## How the boundary is enforced today
48
+
49
+ The package differentiates on **three axes** — none of which is the user's identity.
50
+
51
+ ### 1. By data shape — the only code-enforced line (`sampleOnly` grey-out)
52
+
53
+ `src/menu.ts` gates every analysis-mutating action behind
54
+ `sampleLevelDisabledReason(df)`. On a Spectronaut **Candidates** file (pre-computed DE, no
55
+ per-sample intensities) these items grey out with an explanatory tooltip:
56
+
57
+ > *Not applicable to a Spectronaut Candidates file — it already carries computed
58
+ > differential expression and has no per-sample intensities. Use Volcano Plot, Enrichment
59
+ > Analysis or the UniProt panel, or import the matching Spectronaut Report for sample-level
60
+ > analyses.*
61
+
62
+ Gated (sample-level): Annotate Experiment, Set Log2 Scale, Normalize, Impute, Differential
63
+ Expression, Compute SPC Status, Heatmap, PCA, Group-Mean Correlation, QC Dashboard, Show All
64
+ Visualizations.
65
+
66
+ Always available: Import, Volcano Plot, Enrichment Analysis + Charts, Export Enrichment
67
+ Inputs, SPC Dashboard, Share for Review, UniProt panel.
68
+
69
+ **This gates on the *data*, not the *person*.** It happens to keep a biologist who only ever
70
+ receives Candidates files in the interpretation lane — but it does nothing to stop a
71
+ biologist who opens a **Report** file from running the whole pipeline.
72
+
73
+ ### 2. By workflow stage — the menu grouping mirrors the roles
74
+
75
+ `Import → Annotate → Analyze` is the analyst building the result; `Visualize → Share` is the
76
+ consumer interpreting it. The volcano auto-opening on both DE-completion and Candidates
77
+ import lands the interpreter on the deliverable without making them run the pipeline. This
78
+ is a *convention*, not a restriction.
79
+
80
+ ### 3. By access — view-only sharing (the one real identity boundary)
81
+
82
+ `Share Analysis for Review` publishes a frozen, versioned snapshot and grants the reviewer
83
+ group **View only**. The publish flow's verify-and-rollback gate aborts if the reviewer
84
+ group has any Edit / Share / Delete right at the project, child-space, or umbrella-space
85
+ level. So through the **shared snapshot**, a biologist genuinely cannot change the
86
+ interpretation — they get a read-only copy.
87
+
88
+ ## The gap
89
+
90
+ Enforcement today is **data-shape + access**, not **identity**. Concretely:
91
+
92
+ - A biology user who opens a **Report** file (not a Candidates file, not a shared snapshot)
93
+ sees the full analyst menu enabled and can run/redo DE, re-normalize, re-threshold, and
94
+ re-share. Nothing checks who they are.
95
+ - The view-only guarantee exists **only** for analyses that arrived via Share for Review. A
96
+ biologist working on a live table is unconstrained.
97
+
98
+ CK does not want their biologists to be able to change the interpretation *at all* — which
99
+ data-shape gating cannot guarantee, because it depends on which file they happened to open.
100
+
101
+ ## Target state
102
+
103
+ Add an **identity/role** axis on top of the existing data-shape and access gating, so the
104
+ 🚫 capabilities are unavailable to a biologist regardless of file type.
105
+
106
+ ### What the platform can and cannot enforce
107
+
108
+ This constrains the design, so it comes first. Datagrok's permission model
109
+ (`grok.dapi.permissions`) grants **View / Edit / Share / Delete** on *entities* — projects,
110
+ connections, scripts, queries, packages. There is **no per-function "Execute" permission for
111
+ client-side TypeScript package functions** (a `Func` extends `Entity` but carries no ACL). So
112
+ you **cannot** express "grant the Proteomics group execute on `Normalize`, deny Biologics"
113
+ as a native grant.
114
+
115
+ That leaves two enforcement tiers, with very different strength:
116
+
117
+ - **Application-level group gating (a deterrent, not a wall).** A package function can check
118
+ `grok.dapi.groups.currentUserGroups()` at runtime and refuse to run for non-analysts. This
119
+ is real and has precedent (PowerPack, Grokky), but it runs in the browser and the
120
+ DataFrame mutation is client-side — a determined user could invoke the function from the
121
+ console. It hides analyst actions from biologists; it does **not** guarantee they can't
122
+ change data locally.
123
+ - **Server-enforced boundaries (the real walls).** Three exist: (a) the **view-only shared
124
+ snapshot** — already built (Share for Review); the reviewer group has only View on the
125
+ project, so the server blocks any *save*, and a locally re-run analysis can't be persisted;
126
+ (b) **package-level sharing** — deny the package to a group entirely, but that is
127
+ all-or-nothing and would also remove the volcano/enrichment/UniProt biologists legitimately
128
+ need; (c) **server-side Script/Query Execute permission** — real per-step gating, but only
129
+ for the R scripts, and the package's client-side fallbacks (`limma`/`vsn` → client t-test /
130
+ quantile) are a loophole that would have to be disabled for non-analysts.
131
+
132
+ **The strongest guarantee that already exists is the view-only shared snapshot.** If
133
+ biologists only ever receive analyses via Share for Review, the interpretation of record is
134
+ server-protected today. Everything below is about the *live-table* case.
135
+
136
+ ### Direction (to be specified in an implementation phase)
137
+
138
+ 1. **A "Proteomics Analysts" Datagrok group.** Analyst-only actions key off membership.
139
+ 2. **Menu gating (UX layer).** Extend the `sampleOnly` predicate in `src/menu.ts` to an
140
+ `analystOnly` predicate that also greys out (with a clear reason) when the current user is
141
+ not in the analysts group — so interpretation-changing items disappear for biologists on
142
+ *any* table, not just Candidates. This is a deterrent, not a security boundary.
143
+ 3. **Handler gating (defense in depth, still client-side).** Guard the mutating handlers in
144
+ `src/package.ts` (where `requireSampleLevelData` already lives) so a directly-invoked
145
+ function also refuses for non-analysts. This closes the menu-bypass path but, being
146
+ client-side, is still not a hard wall — the console can reach the same code.
147
+ 4. **The hard wall stays server-side.** For a genuine guarantee, rely on the view-only shared
148
+ snapshot as the default biologist entry point; a true block on *live* tables would require
149
+ moving the mutating steps to server-side Scripts with Execute permission **and** disabling
150
+ the client fallbacks for non-analysts (a larger architectural change — scope only if
151
+ biologists must edit live tables and still be hard-blocked).
152
+
153
+ Open questions for the implementation phase: whether Enrichment re-runs count as "changing
154
+ the interpretation" (currently treated as non-destructive exploration); where CK's biologists
155
+ actually work (shared snapshots only vs. live files — this decides whether steps 2–4 are even
156
+ needed); how the analysts group is provisioned per client/deployment; and whether to expose
157
+ an explicit read-only "Reviewer mode" toggle vs. inferring it from group membership.
158
+
159
+ ## See also
160
+
161
+ - [`README.md` → What you can achieve](../README.md#what-you-can-achieve) — the outcome-led persona intro
162
+ - [`CLAUDE.md` → Menu architecture](../CLAUDE.md) — how the ribbon menu and `isEnabled` grey-out are built
163
+ - `src/menu.ts` — `sampleLevelDisabledReason`, the `sampleOnly` gate
164
+ - `src/package.ts` — `requireSampleLevelData`, the handler-level guards
165
+ - `src/publishing/` — the Share for Review view-only publish flow
@@ -0,0 +1,264 @@
1
+ # Demo Datasets
2
+
3
+ Sample search-engine outputs that exercise every import path and the full analysis
4
+ pipeline (annotate → normalize → impute → differential expression → enrichment →
5
+ visualize), plus the fixtures the package's tests pin against. They are browsable in the
6
+ platform under **Files | App Data | Proteomics | demo**.
7
+
8
+ Most carry an engineered or known-ground-truth signal — spike-in standards or species
9
+ mixed at fixed ratios between conditions — so the differential-expression and volcano
10
+ results are checkable against the truth, not just plausible.
11
+
12
+ ## Which dataset should I use?
13
+
14
+ | Dataset | Vendor / format | Acquisition | Best for |
15
+ |---------|-----------------|-------------|----------|
16
+ | `cptac-spike-in.txt` | MaxQuant `proteinGroups.txt` | DDA | The full pipeline on a real benchmark with known UPS spike-in truth |
17
+ | `proteinGroups.txt` | MaxQuant `proteinGroups.txt` | DDA | A fast, tiny MaxQuant import / UI smoke test |
18
+ | `fragpipe-smoke-test.tsv` | FragPipe `combined_protein.tsv` | DDA | The FragPipe path + UniProt panel (real accessions) with an engineered volcano |
19
+ | `spectronaut-hye-mix.tsv` | Spectronaut report (long) | DIA | Long-format DIA import and the three-species (HYE) ground-truth story |
20
+ | `spectronaut-hye-demo.tsv` | Spectronaut report (long, slim) | DIA | **The registered `Proteomics Demo`** — the full pipeline's richest endpoint, run end to end |
21
+ | `enrichment-demo.csv` | Engineered human DE result | — | **The registered `Proteomics Enrichment Demo`** — a single-organism pathway-enrichment story |
22
+ | `spectronaut-hye-candidates.tsv` | Spectronaut Candidates | DIA | The pre-computed-DE shortcut (straight to volcano/enrichment) |
23
+ | `spectronaut-hye-precursor*.{tsv,json}` | Spectronaut precursor / aggregated | DIA | Streaming-aggregation import and its golden-file equivalence tests |
24
+
25
+ The two HYE files (`spectronaut-hye-mix.tsv` and `spectronaut-hye-candidates.tsv`) tell the
26
+ same biological story from two angles — per-sample quantities vs. pre-computed
27
+ fold-change — so they pair well for comparing the package's own DE against a vendor-shaped
28
+ result.
29
+
30
+ ## proteinGroups.txt
31
+
32
+ | Property | Value |
33
+ |----------|-------|
34
+ | **Format** | MaxQuant `proteinGroups.txt` (wide, tab-separated) |
35
+ | **Source** | Synthetic — generated for development and testing |
36
+ | **Organism** | Human |
37
+ | **Proteins** | 27 |
38
+ | **Samples** | 6 (Sample1–Sample6) |
39
+ | **Quantification** | LFQ intensity |
40
+ | **Columns** | 17 (Protein IDs, Gene names, Protein names, filter flags, LFQ intensities, coverage, peptide counts) |
41
+ | **Size** | 3.7 KB |
42
+
43
+ Minimal MaxQuant output suitable for quick import testing and UI development. Includes
44
+ `Potential contaminant`, `Reverse`, and `Only identified by site` filter columns.
45
+
46
+ ## cptac-spike-in.txt
47
+
48
+ | Property | Value |
49
+ |----------|-------|
50
+ | **Format** | MaxQuant `proteinGroups.txt` (wide, tab-separated) |
51
+ | **Source** | CPTAC spike-in study — processed through MaxQuant |
52
+ | **Organism** | Human (with UPS spike-in standards) |
53
+ | **Proteins** | 1,569 |
54
+ | **Samples** | 6 (two conditions: 6A and 6B, 3 replicates each) |
55
+ | **Quantification** | LFQ intensity and raw Intensity |
56
+ | **Columns** | 80 (full MaxQuant output including peptide counts, sequence coverage, identification types, MS/MS counts) |
57
+ | **Size** | 4.6 MB |
58
+
59
+ Full-scale MaxQuant output from the CPTAC spike-in benchmark. Two conditions (6A vs 6B) with
60
+ known differentially abundant UPS proteins spiked into a constant yeast background. Ideal for
61
+ testing the complete pipeline: import, normalization, imputation, and differential expression.
62
+
63
+ ## fragpipe-smoke-test.tsv
64
+
65
+ | Property | Value |
66
+ |----------|-------|
67
+ | **Format** | FragPipe `combined_protein.tsv` (wide, tab-separated) |
68
+ | **Source** | Synthetic — generated to exercise the FragPipe parser |
69
+ | **Organism** | Human (plus one bovine contaminant) |
70
+ | **Proteins** | 10 (8 targets + 1 `contam_` + 1 `rev_` decoy) |
71
+ | **Samples** | 4 (Ctrl_1, Ctrl_2, Treat_1, Treat_2 — two conditions × two replicates) |
72
+ | **Quantification** | MaxLFQ Intensity, Intensity, Razor Intensity (all three per sample) |
73
+ | **Columns** | 19 (Protein, Protein ID, Entry Name, Gene, Length, Organism, Description + 3 × 4 sample intensity columns) |
74
+ | **Size** | 2.1 KB |
75
+
76
+ Minimal FragPipe output for smoke-testing import and the full analysis pipeline. Real UniProt
77
+ accessions (TP53, BRCA1, EGFR, AKT1, MTOR, F2, PRKCD, HRAS) so the UniProt context panel
78
+ resolves. Includes a `contam_BOVIN_CASEIN` row and a `rev_sp|P12345|...` decoy row to exercise
79
+ the parser's contaminant/decoy filter. Differential abundance is engineered: TP53/AKT1/F2 up
80
+ in Treat, BRCA1/PRKCD down, EGFR/MTOR/HRAS unchanged — gives a predictable volcano-plot pattern.
81
+
82
+ ## spectronaut-hye-mix.tsv
83
+
84
+ | Property | Value |
85
+ |----------|-------|
86
+ | **Format** | Spectronaut report (long, tab-separated) |
87
+ | **Source** | [SpectroPipeR](https://github.com/stemicha/SpectroPipeR) — HYE species mix benchmark (`inst/extdata/SN_test_HYE_mix_file.tsv`) |
88
+ | **Organism** | Human / Yeast / *E. coli* three-species mix |
89
+ | **Proteins** | 93 protein groups |
90
+ | **Samples** | 8 runs (two conditions: HYE mix A and HYE mix B, 4 replicates each) |
91
+ | **Quantification** | PG.Quantity (protein group), FG.MS2Quantity (fragment), PG.IBAQ |
92
+ | **Columns** | 35 (R.FileName, R.Condition, R.Replicate, PG.ProteinGroups, PG.Organisms, EG.Qvalue, EG.ModifiedPeptide, FG.Charge, and more) |
93
+ | **Instrument** | timsTOF Pro2 |
94
+ | **Size** | 5.0 MB |
95
+
96
+ Native Spectronaut DIA-MS long-format report from a three-species spike-in experiment. Each row
97
+ is a peptide precursor measurement across runs. Human, yeast, and *E. coli* proteins are mixed at
98
+ known ratios between conditions A and B, providing ground-truth differential abundance. Useful for
99
+ testing long-format import and DIA-specific workflows.
100
+
101
+ ## spectronaut-hye-demo.tsv
102
+
103
+ | Property | Value |
104
+ |----------|-------|
105
+ | **Format** | Spectronaut report (long, tab-separated) — slimmed to the 7 columns the parser reads |
106
+ | **Source** | **Derived** from `spectronaut-hye-mix.tsv`: kept `R.FileName, R.Condition, R.Replicate, PG.ProteinGroups, PG.Organisms, PG.IBAQ, EG.Qvalue`, and scaled `PG.IBAQ` ×1000 into realistic intensity magnitudes. |
107
+ | **Organism** | Human / Yeast / *E. coli* three-species mix |
108
+ | **Proteins** | 93 protein groups |
109
+ | **Samples** | 8 runs (HYE mix A and HYE mix B, 4 replicates each) |
110
+ | **Quantification** | PG.IBAQ (scaled to realistic magnitude) |
111
+ | **Columns** | 7 |
112
+ | **Signal** | client-side Welch t-test + BH FDR yields ~45 significant (E. coli 27 + yeast 17 + human 1), log2FC up to ≈ 2.5 |
113
+ | **Size** | 1.1 MB |
114
+
115
+ Backs the package's single registered **`Proteomics Demo`** (`meta.demoPath: Bioinformatics |
116
+ Proteomics Differential Expression`). The demo imports this file and runs the whole pipeline —
117
+ import → impute → differential expression → volcano + heatmap — landing on the richest analysis
118
+ endpoint with no R environment and no manual steps. It also opens a **QC dashboard** on a second
119
+ tab and pre-selects the top-significant protein so its **UniProt** entry is already showing in the
120
+ context panel. Enrichment is intentionally excluded: g:Profiler enrichment assumes one organism,
121
+ and this is a three-species mix, so it would only map the human subset and mislead.
122
+
123
+ Why a separate file rather than reusing `spectronaut-hye-mix.tsv`: that fixture's `PG.IBAQ`
124
+ values were scaled *down* for size (max ≈ 34 k), which lands them in the ambiguous band where the
125
+ parser's log2-vs-raw heuristic (`detectLog2Status`) wrongly concludes the data is already
126
+ log2-transformed and skips the transform — producing meaningless linear "fold changes" (± thousands).
127
+ Scaling every intensity by a constant leaves fold-changes and significance **unchanged** (log2FC is
128
+ a difference of logs) but restores realistic magnitudes so the parser log2-transforms correctly.
129
+ The result is the textbook HYE outcome: the two spiked species (E. coli, yeast) separate on the
130
+ volcano while the constant human background stays flat. Regenerate with:
131
+
132
+ ```
133
+ awk -F'\t' 'BEGIN{OFS="\t"; split("R.FileName,R.Condition,R.Replicate,PG.ProteinGroups,PG.Organisms,PG.IBAQ,EG.Qvalue", w, ",")}
134
+ NR==1{for(i=1;i<=NF;i++)h[$i]=i; s=""; for(k=1;k<=length(w);k++)s=s (k>1?OFS:"") w[k]; print s; next}
135
+ {o=""; for(k=1;k<=length(w);k++){c=w[k]; v=(c in h)?$(h[c]):""; if(c=="PG.IBAQ"&&v!=""&&v!="NA"&&v!="NaN")v=v*1000; o=o (k>1?OFS:"") v} print o}' \
136
+ spectronaut-hye-mix.tsv > spectronaut-hye-demo.tsv
137
+ ```
138
+
139
+ ## enrichment-demo.csv
140
+
141
+ | Property | Value |
142
+ |----------|-------|
143
+ | **Format** | Pre-computed DE result (CSV): `Protein ID, Gene, log2FC, p-value, adj.p-value, significant` |
144
+ | **Source** | **Engineered for demonstration.** Real HGNC gene symbols + UniProt accessions; fold-changes and p-values are synthetic. |
145
+ | **Organism** | Human (single organism — enrichment requires one) |
146
+ | **Proteins** | 119 (30 up, 25 down, 64 non-significant background) |
147
+ | **Signal** | UP = cell cycle / mitosis; DOWN = oxidative phosphorylation; background = a diverse, unrelated set |
148
+ | **Size** | 4.5 KB |
149
+
150
+ Backs the registered **`Proteomics Enrichment Demo`** (`meta.demoPath: Proteomics | Enrichment
151
+ Analysis`). The demo loads this as a pre-computed DE result, opens the volcano, runs g:Profiler
152
+ over-representation analysis (GO / KEGG / Reactome / WikiPathways), and docks the enrichment
153
+ charts cross-linked to the volcano — selecting a term highlights its proteins.
154
+
155
+ Why engineered rather than a real dataset: enrichment assumes a **single organism**, which rules
156
+ out the three-species HYE files, and it needs a **coherent** regulated set so the returned terms
157
+ are recognizable. The two regulated sets are drawn from textbook, strongly-annotated pathways
158
+ (cell cycle up, oxidative phosphorylation down), so g:Profiler returns crisp terms — e.g. KEGG
159
+ "Cell cycle" and "Oxidative phosphorylation" at FDR < 1e-15. Gene symbols are real (g:Profiler
160
+ maps them); accessions are real (the UniProt panel resolves); only the statistics are synthetic.
161
+ Regenerate with `bash tools/generate-enrichment-fixture.sh` (the gene lists live in that script).
162
+
163
+ ## spectronaut-hye-candidates.tsv
164
+
165
+ | Property | Value |
166
+ |----------|-------|
167
+ | **Format** | Spectronaut Candidates report (wide, tab-separated, pre-computed DE) |
168
+ | **Source** | **Derived** from `spectronaut-hye-mix.tsv` via this package's own Welch's t-test + BH FDR. Regenerate with `node tools/generate-spectronaut-candidates-fixture.mjs`. |
169
+ | **Comparison** | HYE mix B / HYE mix A (single comparison) |
170
+ | **Proteins** | 93 protein groups (30 Human + 30 Yeast + 30 *E. coli* + 3 other) |
171
+ | **Columns** | 18 (Valid, Comparison, Condition Numerator/Denominator, # of Ratios, Group, AVG Group Quantity Num/Den, AVG Log2 Ratio, Absolute AVG Log2 Ratio, % Change, Ratio, Pvalue, Qvalue, ProteinGroups, Genes, UniProtIds, Organisms) |
172
+ | **Signal** | log2FC range ≈ [−2.46, +3.66]; 43 significant at \|log2FC\| ≥ 1 ∧ q ≤ 0.05 (26 up, 17 down) |
173
+ | **Size** | 20 KB |
174
+
175
+ Exercises the `Proteomics | Import | Spectronaut Candidates...` path with values that line up
176
+ with the source PG file, so the two HYE fixtures tell the same biological story from different
177
+ angles. **Not a verbatim Spectronaut export** — we don't have Spectronaut here, so the script
178
+ does its own DE math and lays it out in Spectronaut's Candidates column shape. Schema matches
179
+ real Spectronaut Candidates output closely enough to round-trip through the importer; numerical
180
+ values are ours, not Biognosys's.
181
+
182
+ ## spectronaut-hye-precursor.tsv
183
+
184
+ | Property | Value |
185
+ |----------|-------|
186
+ | **Format** | Spectronaut report (long, tab-separated, precursor/fragment-level) |
187
+ | **Source** | Synthetic — generated to exercise the streaming Spectronaut import path. Regenerate with `node tools/generate-spectronaut-precursor-fixture.mjs`. |
188
+ | **Organism** | Human / Yeast / *E. coli* three-species mix (synthetic) |
189
+ | **Proteins** | 41 protein groups (39 passing + 1 `CON__` + 1 `REV__`) |
190
+ | **Samples** | 6 runs (two conditions: CondA / CondB, 3 replicates each) |
191
+ | **Quantification** | PG.Quantity (constant per protein × condition × replicate) |
192
+ | **Columns** | 11 (R.FileName, R.Condition, R.Replicate, PG.ProteinGroups, PG.Organisms, PG.Quantity, EG.Qvalue, PEP.StrippedSequence, EG.ModifiedPeptide, FG.Charge, FG.Id) |
193
+ | **Size** | ~44 KB |
194
+
195
+ Small synthetic precursor-level Spectronaut report: ≥2 distinct precursor/fragment
196
+ rows per protein × sample. Carries the D-01 precursor signature columns
197
+ (`EG.ModifiedPeptide` / `FG.Charge` / `PEP.StrippedSequence`) so the header-sniff
198
+ routes it to the streaming aggregator, uses `CondA`/`CondB`, and carries **no**
199
+ `PG.Genes`/`PG.ProteinAccessions` columns (the real `spectronaut-hye-mix.tsv`
200
+ lacks them too). Deliberately includes one `CON__` row, one `REV__` row, one
201
+ protein mixing a passing precursor with a >0.01 sub-threshold one, one
202
+ non-numeric (`Profiled`) q-value protein, and one empty-string q-value protein so
203
+ every Spectronaut filter branch is exercised by a single fixture.
204
+
205
+ ## spectronaut-hye-precursor-golden.tsv
206
+
207
+ | Property | Value |
208
+ |----------|-------|
209
+ | **Format** | Aggregated Spectronaut report (one row per protein × condition × replicate, tab-separated) |
210
+ | **Source** | **Derived** — verbatim duckdb output of `tools/spectronaut-aggregate.sh` over `spectronaut-hye-precursor.tsv`. Regenerate with `tools/spectronaut-aggregate.sh files/demo/spectronaut-hye-precursor.tsv files/demo/spectronaut-hye-precursor-golden.tsv`. |
211
+ | **Proteins** | 39 (the `CON__`/`REV__` decoys are dropped by the WHERE filter) |
212
+ | **Samples** | 6 (CondA / CondB × 3 replicates) |
213
+ | **Rows** | 234 data rows + header |
214
+ | **Columns** | 6 (PG.ProteinGroups, R.Condition, R.Replicate, R.FileName, PG.Quantity, EG.Qvalue) |
215
+ | **Size** | ~12 KB |
216
+
217
+ The D-04 equivalence oracle: the real duckdb aggregation of the fixture, not a
218
+ hand-derived approximation. The Plan-03 golden test compares the streaming
219
+ TypeScript aggregator's output against this file.
220
+
221
+ ## spectronaut-hye-precursor-golden.json
222
+
223
+ | Property | Value |
224
+ |----------|-------|
225
+ | **Format** | JSON map `{ "<protein><condition>_<replicate>": { "quantity": number, "qvalue": number } }` |
226
+ | **Source** | **Transcribed verbatim** from `spectronaut-hye-precursor-golden.tsv` — no re-aggregation. Regenerate with `node tools/derive-precursor-golden-sidecar.mjs`. |
227
+ | **Entries** | 234 (one per surviving protein × condition × replicate) |
228
+ | **Size** | ~9 KB |
229
+
230
+ Read by `grok test` as the in-test oracle when committed-file reads are
231
+ unavailable in the test runner. It is **derived FROM** the golden `.tsv` and
232
+ never re-aggregated, so the equivalence test stays pinned to real duckdb output;
233
+ re-running the deriver against an unchanged golden produces a byte-identical JSON.
234
+
235
+ ### Flip caveat & regeneration order
236
+
237
+ The committed `tools/spectronaut-aggregate.sql` carries a **reference-file-only**
238
+ DMD↔WT `R.Condition` correction (a one-off fix for the mislabeled
239
+ `2026-05-13 BP DMD WT.tsv` reference file). It is a structural **no-op** on this
240
+ `CondA`/`CondB` fixture, which is exactly why the same script doubles as both the
241
+ documented manual fallback **and** the test oracle without perturbing the golden.
242
+ The committed SQL also **drops** the two unused `any_value` carry-along SELECT
243
+ terms for the gene-symbol and protein-accession columns present in the `/tmp`
244
+ original — a documented divergence, because the package's Spectronaut data does
245
+ not carry those columns and keeping them would Binder-Error duckdb over this
246
+ fixture.
247
+
248
+ The fixture → golden `.tsv` → golden `.json` chain **must be regenerated in
249
+ order**, or the artifacts silently drift:
250
+
251
+ 1. `node tools/generate-spectronaut-precursor-fixture.mjs`
252
+ 2. `tools/spectronaut-aggregate.sh files/demo/spectronaut-hye-precursor.tsv files/demo/spectronaut-hye-precursor-golden.tsv`
253
+ 3. `node tools/derive-precursor-golden-sidecar.mjs`
254
+
255
+ ## License
256
+
257
+ - **proteinGroups.txt** — Synthetic data, no restrictions.
258
+ - **cptac-spike-in.txt** — Public benchmark data from the Clinical Proteomic Tumor Analysis Consortium.
259
+ - **fragpipe-smoke-test.tsv** — Synthetic data, no restrictions.
260
+ - **spectronaut-hye-mix.tsv** — From SpectroPipeR, licensed under MIT.
261
+ - **spectronaut-hye-candidates.tsv** — Derived from `spectronaut-hye-mix.tsv` (MIT). DE values computed by this package; no restrictions.
262
+ - **spectronaut-hye-precursor.tsv** — Synthetic data, no restrictions.
263
+ - **spectronaut-hye-precursor-golden.tsv** — Derived (duckdb aggregation) from `spectronaut-hye-precursor.tsv` (synthetic); no restrictions.
264
+ - **spectronaut-hye-precursor-golden.json** — Transcribed from `spectronaut-hye-precursor-golden.tsv` (synthetic); no restrictions.