@datagrok/proteomics 1.0.1 → 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.
- package/CHANGELOG.md +52 -3
- package/CLAUDE.md +178 -0
- package/README.md +195 -3
- package/detectors.js +152 -9
- package/dist/package-test.js +1 -1744
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -146
- package/dist/package.js.map +1 -1
- package/docs/personas-and-capabilities.md +165 -0
- package/files/demo/README.md +264 -0
- package/files/demo/cptac-spike-in.txt +1571 -0
- package/files/demo/enrichment-demo.csv +120 -0
- package/files/demo/fragpipe-smoke-test.tsv +11 -0
- package/files/demo/proteinGroups.txt +28 -0
- package/files/demo/spectronaut-hye-candidates.tsv +94 -0
- package/files/demo/spectronaut-hye-demo.tsv +8761 -0
- package/files/demo/spectronaut-hye-mix.tsv +8761 -0
- package/files/demo/spectronaut-hye-precursor-golden.json +938 -0
- package/files/demo/spectronaut-hye-precursor-golden.tsv +235 -0
- package/files/demo/spectronaut-hye-precursor.tsv +493 -0
- package/images/enrichment-crosslink.png +0 -0
- package/images/enrichment-term-selected.png +0 -0
- package/images/hero.png +0 -0
- package/images/pipeline.svg +80 -0
- package/package.json +87 -63
- package/scripts/deqms_de.R +60 -0
- package/scripts/limma_de.R +42 -0
- package/scripts/vsn_normalize.R +19 -0
- package/src/analysis/differential-expression.ts +450 -0
- package/src/analysis/enrichment-export.ts +101 -0
- package/src/analysis/enrichment.ts +602 -0
- package/src/analysis/experiment-setup.ts +199 -0
- package/src/analysis/imputation.ts +407 -0
- package/src/analysis/log2-scale.ts +139 -0
- package/src/analysis/normalization.ts +255 -0
- package/src/analysis/pca.ts +254 -0
- package/src/analysis/spc-storage.ts +515 -0
- package/src/analysis/spc.ts +544 -0
- package/src/analysis/subcellular-location.ts +431 -0
- package/src/demo/enrichment-demo.ts +94 -0
- package/src/demo/proteomics-demo.ts +123 -0
- package/src/global.d.ts +15 -0
- package/src/menu.ts +133 -0
- package/src/package-api.ts +136 -14
- package/src/package-test.ts +45 -20
- package/src/package.g.ts +161 -0
- package/src/package.ts +1029 -17
- package/src/panels/protein-focus.ts +63 -0
- package/src/panels/published-analysis-panel.ts +151 -0
- package/src/panels/uniprot-panel.ts +349 -0
- package/src/parsers/fragpipe-parser.ts +200 -0
- package/src/parsers/generic-parser.ts +197 -0
- package/src/parsers/maxquant-parser.ts +162 -0
- package/src/parsers/shared-utils.ts +163 -0
- package/src/parsers/spectronaut-candidates-parser.ts +307 -0
- package/src/parsers/spectronaut-parser.ts +604 -0
- package/src/publishing/assert-published-shape.ts +260 -0
- package/src/publishing/post-open-recovery.ts +104 -0
- package/src/publishing/publish-project.ts +515 -0
- package/src/publishing/publish-settings.ts +59 -0
- package/src/publishing/publish-state.ts +316 -0
- package/src/publishing/share-dialog.ts +171 -0
- package/src/publishing/trim-dataframe.ts +247 -0
- package/src/tests/analysis.ts +658 -0
- package/src/tests/enrichment-export.ts +61 -0
- package/src/tests/enrichment-visualization.ts +340 -0
- package/src/tests/enrichment.ts +224 -0
- package/src/tests/fragpipe-e2e.ts +74 -0
- package/src/tests/fragpipe-parser.ts +147 -0
- package/src/tests/gene-label-resolver.ts +387 -0
- package/src/tests/generic-parser.ts +152 -0
- package/src/tests/group-mean-correlation.ts +139 -0
- package/src/tests/log2-scale.ts +93 -0
- package/src/tests/organisms.ts +56 -0
- package/src/tests/parsers.ts +182 -0
- package/src/tests/publish-roundtrip.ts +584 -0
- package/src/tests/publish-spike.ts +377 -0
- package/src/tests/qc-dashboard.ts +210 -0
- package/src/tests/smart-pathway-filter.ts +193 -0
- package/src/tests/spc-formula-lines-spike.ts +129 -0
- package/src/tests/spc.ts +640 -0
- package/src/tests/spectronaut-candidates-e2e.ts +140 -0
- package/src/tests/spectronaut-candidates-parser.ts +398 -0
- package/src/tests/spectronaut-parser.ts +668 -0
- package/src/tests/subcellular-location.ts +361 -0
- package/src/tests/uniprot-panel.ts +202 -0
- package/src/tests/volcano.ts +603 -0
- package/src/utils/column-detection.ts +28 -0
- package/src/utils/gene-label-resolver.ts +443 -0
- package/src/utils/organisms.ts +82 -0
- package/src/utils/proteomics-types.ts +30 -0
- package/src/viewers/enrichment-viewers.ts +274 -0
- package/src/viewers/group-mean-correlation.ts +218 -0
- package/src/viewers/heatmap.ts +168 -0
- package/src/viewers/pca-plot.ts +169 -0
- package/src/viewers/qc-computations.ts +266 -0
- package/src/viewers/qc-dashboard.ts +176 -0
- package/src/viewers/spc-dashboard.ts +755 -0
- package/src/viewers/volcano.ts +690 -0
- package/test-console-output-1.log +2055 -0
- package/test-record-1.mp4 +0 -0
- package/tools/derive-precursor-golden-sidecar.mjs +81 -0
- package/tools/generate-enrichment-fixture.sh +160 -0
- package/tools/generate-spectronaut-candidates-fixture.mjs +212 -0
- package/tools/generate-spectronaut-precursor-fixture.mjs +128 -0
- package/tools/spectronaut-aggregate.sh +46 -0
- package/tools/spectronaut-aggregate.sql +80 -0
- package/tsconfig.json +18 -71
- package/webpack.config.js +86 -45
- package/.eslintignore +0 -1
- package/.eslintrc.json +0 -56
- package/LICENSE +0 -674
- package/package.png +0 -0
- package/scripts/number_antibody.py +0 -190
- package/scripts/number_antibody_abnumber.py +0 -177
- package/scripts/number_antibody_anarci.py +0 -200
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
##
|
|
1
|
+
# Proteomics changelog
|
|
2
|
+
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
- **Shared enrichment charts now survive reopen** — a published/shared analysis's enrichment
|
|
6
|
+
dot and bar charts no longer lose their value column (the "Column negLog10FDR does not
|
|
7
|
+
exist" error) when the project is reopened, and the Up/Down term tables no longer leak
|
|
8
|
+
into the project as extra tables. The charts are now self-contained on the enrichment
|
|
9
|
+
frame and split by direction via a per-viewer filter.
|
|
10
|
+
- **Volcano opens automatically on Candidates import** — importing a Spectronaut Candidates
|
|
11
|
+
file now lands you on the volcano immediately, matching the Report → Differential
|
|
12
|
+
Expression path (Candidates arrive with the result already computed, so the pipeline's DE
|
|
13
|
+
step is skipped).
|
|
14
|
+
- **Personas & capabilities documentation** — a reference describing what the proteomics
|
|
15
|
+
analyst vs. the biology scientist can do and how that boundary is enforced.
|
|
16
|
+
|
|
17
|
+
## 0.2.0
|
|
18
|
+
|
|
19
|
+
- **Organism-aware subcellular-location coloring** — the volcano's "color by subcellular
|
|
20
|
+
location" now fetches UniProt annotations for the experiment's organism (persisted as a
|
|
21
|
+
`proteomics.organism` tag from the Enrichment dialog), so non-human data is no longer
|
|
22
|
+
mis-colored by human entries. The taxonomy filter applies only to the reviewed-by-gene
|
|
23
|
+
fallback; accession lookups stay unfiltered, and all 9 supported organisms are covered.
|
|
24
|
+
- **Internal consistency** — significance thresholds, the direction palette, and column-name
|
|
25
|
+
constants are now single-sourced instead of duplicated across files; the differential-
|
|
26
|
+
expression FDR cutoff is wired through to the BH correction.
|
|
27
|
+
- **README** — illustrated with the main analysis view, an authored pipeline diagram, and an
|
|
28
|
+
enrichment→volcano cross-link walkthrough.
|
|
29
|
+
|
|
30
|
+
## 0.1.0
|
|
31
|
+
|
|
32
|
+
Initial release — mass spectrometry-based proteomics analysis, carrying a study from
|
|
33
|
+
search-engine output to biological interpretation inside Datagrok.
|
|
34
|
+
|
|
35
|
+
- **Import** — MaxQuant (`proteinGroups.txt`), Spectronaut Report (PG-level, including
|
|
36
|
+
streaming aggregation of long-form precursor exports), Spectronaut Candidates
|
|
37
|
+
(pre-computed differential expression), FragPipe (`combined_protein.tsv`), and a generic
|
|
38
|
+
CSV/TSV column-mapping importer. Contaminant/decoy filtering, log2 transformation, and
|
|
39
|
+
semantic-type tagging are applied on import.
|
|
40
|
+
- **Pipeline** — experiment annotation (group assignment), normalization
|
|
41
|
+
(median / quantile / VSN), missing-value imputation (kNN / MinProb / mean / median /
|
|
42
|
+
zero), and differential expression cascading DEqMS → limma → client-side Welch's t-test.
|
|
43
|
+
- **Visualization** — volcano, clustered expression heatmap, sample-level PCA, group-mean
|
|
44
|
+
correlation, QC dashboard (MA / CV / missingness / intensity trend), and an SPC dashboard
|
|
45
|
+
with Nelson-rule instrument monitoring.
|
|
46
|
+
- **Biological interpretation** — g:Profiler over-representation analysis (GO, KEGG,
|
|
47
|
+
Reactome, WikiPathways across 9 organisms) with dot/bar charts cross-linked to the
|
|
48
|
+
volcano, plus a UniProt context panel for per-protein metadata.
|
|
49
|
+
- **Sharing** — publish read-only, access-verified, versioned review snapshots
|
|
50
|
+
(table + volcano + enrichment) to a reviewer group.
|
|
51
|
+
- R scripts (limma, DEqMS, VSN) run server-side with client-side fallbacks throughout, so
|
|
52
|
+
the package is fully functional without a configured R environment.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Datagrok extension for mass-spectrometry proteomics analysis. Imports search-engine output
|
|
8
|
+
(MaxQuant, Spectronaut, FragPipe, generic CSV/TSV), runs the analysis pipeline
|
|
9
|
+
(annotate groups -> normalize -> impute -> differential expression -> enrichment),
|
|
10
|
+
and adds the matching viewers (volcano, heatmap, PCA, QC dashboard, enrichment charts).
|
|
11
|
+
Exposed in the platform under the top-menu **Proteomics**.
|
|
12
|
+
|
|
13
|
+
Auth / credentials: none. The package only calls public REST APIs (UniProt, g:Profiler).
|
|
14
|
+
R scripts (`scripts/limma_de.R`, `scripts/deqms_de.R`, `scripts/vsn_normalize.R`) run server-side
|
|
15
|
+
via `grok.functions.call(...)` and need a configured Datagrok R compute environment; every
|
|
16
|
+
R path has a client-side TypeScript fallback.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
Functional pipeline. Each step mutates a shared `DG.DataFrame` in-place and records its
|
|
21
|
+
completion as a `proteomics.*` tag on the DataFrame. Downstream functions read those tags
|
|
22
|
+
as preconditions. There is no separate state store.
|
|
23
|
+
|
|
24
|
+
- **`src/package.ts`** — entry point. `PackageFunctions` class with `@grok.decorators.func`
|
|
25
|
+
/ `init` / `panel` methods. Each handler validates that a table is open, checks any
|
|
26
|
+
required `proteomics.*` precondition tag, then delegates to `analysis/` or `viewers/`.
|
|
27
|
+
The **Proteomics** menu is built two ways (see "Menu architecture" below).
|
|
28
|
+
- **`src/menu.ts`** — builds the full **Proteomics** ribbon menu (Import + Annotate /
|
|
29
|
+
Analyze / Visualize / Share) on a table view's `ribbonMenu`, with the `isEnabled` grey-out:
|
|
30
|
+
sample-level items disable themselves on a Spectronaut Candidates table (no per-sample
|
|
31
|
+
intensities). The `buildProteomicsTopMenu` autostart in `package.ts` calls
|
|
32
|
+
`buildProteomicsRibbonMenu` once per Proteomics table view.
|
|
33
|
+
|
|
34
|
+
### Menu architecture (read before touching the menu — non-obvious, verified live)
|
|
35
|
+
|
|
36
|
+
The **Proteomics** menu lives in two independent hosts. A decorator `top-menu` populates
|
|
37
|
+
`grok.shell.topMenu` (the **left-bar main menu**) ONLY; it does NOT populate a table view's
|
|
38
|
+
ribbon. So:
|
|
39
|
+
|
|
40
|
+
- **Left-bar main menu** = decorator `top-menu` strings on the `importX` handlers in
|
|
41
|
+
`package.ts`, e.g. `Proteomics | Import | Spectronaut Candidates...`. This is the
|
|
42
|
+
always-available entry point — reachable with **no table open** (the ribbon shows no
|
|
43
|
+
package menu on the Home/start view). Declaration order = menu order (Candidates first,
|
|
44
|
+
then Report). Only Import is here, because import is the only thing you do without a table.
|
|
45
|
+
- **Ribbon (table view)** = built programmatically in `menu.ts` onto `view.ribbonMenu`, and
|
|
46
|
+
only when a Proteomics table (`proteomics.source` tag) is active. It builds the WHOLE menu
|
|
47
|
+
including its own Import group — the decorator Import does not reach the ribbon, and a
|
|
48
|
+
view's own `ribbonMenu` 'Proteomics' group is what the ribbon shows. Built once per view;
|
|
49
|
+
do NOT rebuild on view activation (`isEnabled` re-evaluates on open — rebuilding the menu
|
|
50
|
+
duplicates it, which was a real bug).
|
|
51
|
+
|
|
52
|
+
To add a menu item: if it's an importer, add a decorator `top-menu` handler in `package.ts`
|
|
53
|
+
(left-bar menu) AND an `imp.item(...)` line in `menu.ts` (ribbon). Otherwise add the handler
|
|
54
|
+
in `package.ts` and an item in the right group in `menu.ts` (pass `sampleOnly` as the
|
|
55
|
+
`isEnabled` option if it needs per-sample data). Don't give the analysis groups decorator
|
|
56
|
+
`top-menu` strings — they'd show in the left-bar menu with no table context and can't grey
|
|
57
|
+
out.
|
|
58
|
+
- **`src/analysis/`** — pure computation that mutates the DataFrame and sets a completion
|
|
59
|
+
tag. One file per step: `experiment-setup.ts` (groups + `getGroups`/`setGroups`),
|
|
60
|
+
`normalization.ts`, `imputation.ts`, `differential-expression.ts`, `pca.ts`, `enrichment.ts`.
|
|
61
|
+
`log2-scale.ts` is the exception — a post-import corrective (Analyze | Set Log2 Scale...) that
|
|
62
|
+
rebuilds the `log2(...)` columns from the pristine originals and *clears* the downstream completion
|
|
63
|
+
tags (base data changed → pipeline must re-run).
|
|
64
|
+
- **`src/parsers/`** — vendor file -> filtered, log2-transformed, semantic-typed DataFrame.
|
|
65
|
+
`maxquant-parser.ts`, `spectronaut-parser.ts` (PG report — per-sample quant),
|
|
66
|
+
`spectronaut-candidates-parser.ts` (Candidates report — pre-computed DE; emits the
|
|
67
|
+
canonical `log2FC` / `p-value` / `adj.p-value` / `significant` shape and sets
|
|
68
|
+
`proteomics.de_complete`, so the pipeline skips Annotate/Normalize/Impute/DE),
|
|
69
|
+
`fragpipe-parser.ts`, `generic-parser.ts`, plus `shared-utils.ts` (log2 transform,
|
|
70
|
+
log2-status detection, delimiter detection, primary-id column extraction). Parsers return
|
|
71
|
+
unnamed DataFrames; the import handler in `package.ts` sets `df.name` from the filename.
|
|
72
|
+
- **`src/viewers/`** — `DG.Viewer` factories that read an already-analysed DataFrame.
|
|
73
|
+
`volcano.ts`, `heatmap.ts`, `pca-plot.ts`, `qc-dashboard.ts` (+ `qc-computations.ts` for
|
|
74
|
+
MA / CV / missingness math), `enrichment-viewers.ts`.
|
|
75
|
+
- **`src/panels/uniprot-panel.ts`** — context-panel widget that fetches per-protein metadata
|
|
76
|
+
on cell click. Registered via `@grok.decorators.panel` with a `semType` filter.
|
|
77
|
+
- **`src/utils/proteomics-types.ts`** — `SEMTYPE` constants. **Single source of truth** for
|
|
78
|
+
every `Proteomics-*` semantic type string. Use these; never inline the strings.
|
|
79
|
+
- **`src/utils/column-detection.ts`** — `findColumn(df, semType, nameHints)` and
|
|
80
|
+
`findProteomicsColumns(df)`. **Use these instead of `df.col('Gene names')`** so the
|
|
81
|
+
package keeps working on tables from new vendors that haven't been semantically tagged.
|
|
82
|
+
- **`detectors.js`** (package root, plain JS — not under `src/`) — semantic-type detectors
|
|
83
|
+
loaded by the platform before the webpack bundle. Mirrors the `SEMTYPE` constants. If you
|
|
84
|
+
add a new semantic type, add a detector here too.
|
|
85
|
+
|
|
86
|
+
### Pipeline shape (read before editing)
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
parse* (parsers/)
|
|
90
|
+
-> grok.shell.addTableView(df)
|
|
91
|
+
-> showAnnotationDialog (analysis/experiment-setup) sets proteomics.groups
|
|
92
|
+
-> showNormalizationDialog (analysis/normalization) sets proteomics.normalized
|
|
93
|
+
-> showImputationDialog (analysis/imputation) sets proteomics.imputed
|
|
94
|
+
-> showDEDialog (analysis/differential-expression) sets proteomics.de_complete (+ proteomics.de_method)
|
|
95
|
+
-> createVolcanoPlot / createExpressionHeatmap / showEnrichmentDialog
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Workflow state is **only** on the DataFrame as tags (see "Tags" below). Group assignments
|
|
99
|
+
are JSON-encoded in `proteomics.groups` — always go through `getGroups(df)` / `setGroups(df, g)`
|
|
100
|
+
in `analysis/experiment-setup.ts`; do not parse the tag yourself.
|
|
101
|
+
|
|
102
|
+
PCA is the one viewer that produces a **new** sample-level DataFrame (rows = samples, not
|
|
103
|
+
proteins). It must open in its own table view — never add the PCA viewer to the protein
|
|
104
|
+
table view. See the `showPcaPlot` handler in `package.ts` for the pattern.
|
|
105
|
+
|
|
106
|
+
### Function-naming convention (load-bearing)
|
|
107
|
+
|
|
108
|
+
The package splits the common shapes by prefix. Match the prefix when adding new code:
|
|
109
|
+
|
|
110
|
+
| Prefix | Shape | Side effect |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `showX(df)` | opens a `ui.dialog(...)` | mutates `df` on OK |
|
|
113
|
+
| `openX(df)` | creates a table view / dashboard | adds to the shell |
|
|
114
|
+
| `createX(df, opts?)` | returns a `DG.Viewer` | none — pure factory |
|
|
115
|
+
| `parseXText(text)` | returns a `DG.DataFrame` | none — caller adds to shell + sets name |
|
|
116
|
+
|
|
117
|
+
Menu paths that open a dialog end with `...`; immediate-action items do not.
|
|
118
|
+
|
|
119
|
+
## Glossary
|
|
120
|
+
|
|
121
|
+
| Concept | Code | Meaning |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| Intensity column | `DG.Column` with `semType = SEMTYPE.INTENSITY` | One sample's per-protein abundance. Raw or log2-transformed; analysis steps operate on the `log2(...)` variants. |
|
|
124
|
+
| Group assignment | `GroupAssignment` interface (`analysis/experiment-setup.ts`); JSON in `proteomics.groups` tag | Maps two named groups (e.g. Control / Treatment) to the intensity columns belonging to each. Required input for normalization, imputation, DE, PCA, enrichment. |
|
|
125
|
+
| DE result | `log2FC`, `p-value`, `adj.p-value`, `significant` columns added by `runDifferentialExpression` / R scripts | Per-protein output of differential expression. Volcano/heatmap require these — they check `proteomics.de_complete`. |
|
|
126
|
+
| Fallback chain | `try { R } catch { client-side }` in `analysis/` | DE runs DEqMS -> limma -> client t-test; VSN -> quantile. R is optional; the package must still function without it. |
|
|
127
|
+
| Cross-DF link (enrichment) | `enrichDf.onCurrentRowChanged` subscription in `viewers/enrichment-viewers.ts` | Selecting a GO/KEGG term row in the enrichment DataFrame highlights the linked proteins in the protein DataFrame's volcano/heatmap. |
|
|
128
|
+
|
|
129
|
+
### DataFrame tags
|
|
130
|
+
|
|
131
|
+
All workflow state lives in tags prefixed `proteomics.`. Checking and setting these tags is
|
|
132
|
+
how the pipeline coordinates between steps — there is no other state store.
|
|
133
|
+
|
|
134
|
+
| Tag | Value | Set by |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| `proteomics.source` | `'maxquant'` / `'spectronaut'` / `'spectronaut-candidates'` / `'fragpipe'` / `'generic'` | parsers |
|
|
137
|
+
| `proteomics.groups` | JSON `GroupAssignment` | `setGroups()` after Annotate Experiment |
|
|
138
|
+
| `proteomics.organism` | g:Profiler code (e.g. `rnorvegicus`) | `setOrganism()` — auto-detected at import from the data's organism column (`detectOrganismCode`), confirmable in Annotate Experiment, and persisted on Enrichment OK; read by enrichment + subcellular-location gene fallback |
|
|
139
|
+
| `proteomics.normalized` | `'true'` | any normalization method |
|
|
140
|
+
| `proteomics.preNormalized` | `'true'` | Spectronaut parser (input was already normalized) |
|
|
141
|
+
| `proteomics.imputed` | `'true'` | any imputation method |
|
|
142
|
+
| `proteomics.de_complete` | `'true'` | DE pipeline completion, or Spectronaut Candidates parser (already-computed DE) |
|
|
143
|
+
| `proteomics.de_method` | `'limma'` / `'deqms'` / `'t-test'` / `'spectronaut'` | DE on completion (which method actually ran) |
|
|
144
|
+
| `proteomics.enrichment` | `'true'` | enrichment DataFrame marker |
|
|
145
|
+
|
|
146
|
+
## Conventions specific to this package
|
|
147
|
+
|
|
148
|
+
- **Look up columns via `findColumn` / `findProteomicsColumns`**, never by raw name. Imports
|
|
149
|
+
from new vendors may not be semantically typed yet, so the helper falls back to name
|
|
150
|
+
hints. Hard-coded `df.col('Gene names')` will silently miss valid columns.
|
|
151
|
+
- **Use `SEMTYPE.*` from `src/utils/proteomics-types.ts`** for every `Proteomics-*` string.
|
|
152
|
+
These are the single source of truth and are mirrored in `detectors.js`.
|
|
153
|
+
- **Set the matching `proteomics.*` tag** when finishing an analysis step. Downstream
|
|
154
|
+
viewers gate on it. If you add a new step, pick a tag name now and document it here.
|
|
155
|
+
- **Always provide a client-side fallback for R script calls.** The DE pipeline cascades
|
|
156
|
+
DEqMS -> limma -> client-side Welch's t-test; normalization cascades VSN -> quantile.
|
|
157
|
+
Never assume the platform R environment is configured.
|
|
158
|
+
- **Idempotency on re-run.** DE is guarded by checking `proteomics.de_complete` in the
|
|
159
|
+
menu handler. Normalization/imputation are not currently guarded — if you add a step that
|
|
160
|
+
adds columns, follow the `ensureFreshFloat` pattern in `viewers/qc-computations.ts`
|
|
161
|
+
(remove the column if it exists, then add it) so re-running doesn't produce duplicates.
|
|
162
|
+
- **PCA opens in a separate table view.** Its sample-level DataFrame has a different row
|
|
163
|
+
count from the protein DataFrame, so `createPcaPlot` returns `{viewer, pcaDf}` and the
|
|
164
|
+
caller does `grok.shell.addTableView(pcaDf)` before docking the viewer. Do not add a PCA
|
|
165
|
+
viewer to the protein table view.
|
|
166
|
+
- **Heatmap clones the DataFrame for filter isolation.** `createExpressionHeatmap` uses
|
|
167
|
+
`df.clone(filter)` so its top-N sort/filter doesn't leak into the volcano sharing the
|
|
168
|
+
same source DataFrame.
|
|
169
|
+
- **Adding a new semantic type:** update `SEMTYPE` in `src/utils/proteomics-types.ts` **and**
|
|
170
|
+
add a detector in `detectors.js`. The README's "Semantic Type Detection" table is part of
|
|
171
|
+
the public contract.
|
|
172
|
+
- **Adding a new parser, analysis step, or viewer:** the file layout for each is documented
|
|
173
|
+
in `.planning/codebase/STRUCTURE.md` under "Where to Add New Code". Follow that contract
|
|
174
|
+
(new file under the matching directory, register handler in `src/package.ts`, add
|
|
175
|
+
precondition tag check, add test under `src/tests/`).
|
|
176
|
+
- **Deeper context:** `.planning/codebase/{ARCHITECTURE,STRUCTURE,CONVENTIONS,CONCERNS,
|
|
177
|
+
INTEGRATIONS,TESTING,STACK}.md` are kept up to date and go well beyond this file. Read
|
|
178
|
+
them when a task is non-trivial; do not duplicate their content here.
|
package/README.md
CHANGED
|
@@ -1,3 +1,195 @@
|
|
|
1
|
-
# Proteomics
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Proteomics
|
|
2
|
+
|
|
3
|
+
Mass spectrometry-based proteomics data analysis [package](https://datagrok.ai/help/develop/#packages)
|
|
4
|
+
for the [Datagrok](https://datagrok.ai) platform.
|
|
5
|
+
|
|
6
|
+
It takes a study from raw search-engine output to a result a biologist can act on —
|
|
7
|
+
*which proteins changed, what pathways they implicate, and what each protein is* — and lets
|
|
8
|
+
you share that result as a read-only snapshot a collaborator can explore without touching
|
|
9
|
+
the raw data or writing a line of code. It covers **label-free quantitative proteomics**
|
|
10
|
+
from both **DDA** (MaxQuant, FragPipe) and **DIA** (Spectronaut) workflows.
|
|
11
|
+
|
|
12
|
+
Open it from the **Proteomics** top menu.
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
*One screen from statistics to biology: the interactive volcano, the clustered expression heatmap, and in-place UniProt annotation for the selected protein.*
|
|
17
|
+
|
|
18
|
+
## Where it fits
|
|
19
|
+
|
|
20
|
+
The package picks up **where the search engine leaves off** and carries the study all the
|
|
21
|
+
way to biological interpretation. It does not replace MaxQuant, FragPipe, DIA-NN or
|
|
22
|
+
Spectronaut, and it does not touch raw instrument files (`.raw`, `.mzML`, `.d`) — you
|
|
23
|
+
bring in the protein/quant table they produce. From there it stands in for the four-to-six
|
|
24
|
+
disconnected desktop tools and hand-exported files that normally sit between that table
|
|
25
|
+
and a finished figure: import, QC, statistics, interpretation, and sharing happen in one
|
|
26
|
+
place, and the result stays reproducible instead of scattered across scripts and
|
|
27
|
+
spreadsheets.
|
|
28
|
+
|
|
29
|
+
## What you can achieve
|
|
30
|
+
|
|
31
|
+
### If you generate the data — the proteomics scientist
|
|
32
|
+
|
|
33
|
+
- **Stand behind your quantification.** Normalization removes between-sample technical
|
|
34
|
+
bias and principled missing-value handling deals with the dropout that is intrinsic to
|
|
35
|
+
MS, so downstream fold-changes reflect biology rather than loading or detection
|
|
36
|
+
artifacts.
|
|
37
|
+
- **Make a defensible significance call.** Statistics built for the small-sample,
|
|
38
|
+
high-dimensional reality of proteomics (limma / DEqMS) give you a ranked, FDR-controlled
|
|
39
|
+
list of changed proteins you can justify to a reviewer — not an ad-hoc cutoff.
|
|
40
|
+
- **Catch problems before they become false discoveries.** Per-run QC and longitudinal
|
|
41
|
+
process control surface a mislabeled channel, a weak replicate, or instrument drift
|
|
42
|
+
across a batch *before* it drives a result.
|
|
43
|
+
- **Hand off something reproducible.** Publish the finished analysis as a versioned,
|
|
44
|
+
read-only snapshot — the collaborator sees exactly what you saw, and a later re-analysis
|
|
45
|
+
supersedes rather than overwrites it.
|
|
46
|
+
|
|
47
|
+
### If you interpret the data — the biology scientist
|
|
48
|
+
|
|
49
|
+
- **See what changed.** An interactive volcano shows which proteins go up or down between
|
|
50
|
+
your conditions and how strongly — sorted, labeled, and clickable, not a static figure.
|
|
51
|
+
- **Understand what it means.** Enrichment collapses a list of hundreds of changed
|
|
52
|
+
proteins into the handful of biological processes, pathways, and complexes that are
|
|
53
|
+
actually over-represented (GO, KEGG, Reactome, WikiPathways) — and selecting a pathway
|
|
54
|
+
highlights its proteins back on the volcano, so statistics and biology stay connected.
|
|
55
|
+
- **Know what each hit is.** Click any protein to pull its name, gene, function, and
|
|
56
|
+
subcellular location from UniProt, in place — no separate database lookups.
|
|
57
|
+
- **Explore it yourself.** Open the shared snapshot and filter, select, and cross-link
|
|
58
|
+
interactively. You don't need the raw files, the analysis environment, or another round
|
|
59
|
+
trip through the analyst to ask your own follow-up questions.
|
|
60
|
+
|
|
61
|
+
## Supported inputs
|
|
62
|
+
|
|
63
|
+
| Format | File | Notes |
|
|
64
|
+
|--------|------|-------|
|
|
65
|
+
| **MaxQuant** | `proteinGroups.txt` | DDA. LFQ / Razor / iBAQ intensities; contaminant & reverse-hit filtering |
|
|
66
|
+
| **Spectronaut — Report** | PG-level export | DIA. Pivots long-form precursor exports to a protein × sample matrix; streams multi-GB files; q-value filtering |
|
|
67
|
+
| **Spectronaut — Candidates** | pre-computed DE export | DIA. Already-computed fold-change / FDR per protein; skips straight to visualization |
|
|
68
|
+
| **FragPipe** | `combined_protein.tsv` | DDA. MaxLFQ / Intensity / Razor; Philosopher contaminant filtering |
|
|
69
|
+
| **Generic matrix** | any CSV/TSV | Column-mapping dialog; auto-detects delimiter and log2 status |
|
|
70
|
+
|
|
71
|
+
> DIA-NN is **not** currently supported as a direct importer — bring DIA-NN output in via
|
|
72
|
+
> the **Generic matrix** path, or as a Spectronaut-style matrix.
|
|
73
|
+
|
|
74
|
+
## Workflow
|
|
75
|
+
|
|
76
|
+
The pipeline runs as a sequence of steps from the **Proteomics** menu. Each step records
|
|
77
|
+
its completion on the table, and downstream steps read those as preconditions, so the
|
|
78
|
+
menu greys out actions that don't yet apply (and items that need per-sample intensities
|
|
79
|
+
are disabled on the pre-computed Spectronaut Candidates table).
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
### Import
|
|
84
|
+
`Spectronaut Candidates...` · `Spectronaut Report...` · `MaxQuant...` · `FragPipe...` ·
|
|
85
|
+
`Generic Matrix...` — also available from the left-bar main menu with no table open.
|
|
86
|
+
|
|
87
|
+
### Annotate
|
|
88
|
+
- **Annotate Experiment** — assign intensity columns to two named groups
|
|
89
|
+
(e.g. Control vs. Treatment); required input for normalization, imputation, DE, PCA and
|
|
90
|
+
enrichment.
|
|
91
|
+
|
|
92
|
+
### Analyze
|
|
93
|
+
- **Normalize** — median centering, quantile normalization, or VSN (variance-stabilizing;
|
|
94
|
+
R, with a quantile fallback).
|
|
95
|
+
- **Impute Missing Values** — k-nearest-neighbor, MinProb (Perseus-style downshifted
|
|
96
|
+
draw), mean, median, or zero.
|
|
97
|
+
- **Differential Expression** — DEqMS (peptide-count-weighted variance) → limma
|
|
98
|
+
(empirical-Bayes moderated t-test) → client-side Welch's t-test, cascading down on
|
|
99
|
+
availability. Adds `log2FC`, `p-value`, `adj.p-value` and a `significant` flag.
|
|
100
|
+
- **Enrichment Analysis** — over-representation against GO (BP/MF/CC), KEGG, Reactome and
|
|
101
|
+
WikiPathways through g:Profiler, for 9 model organisms (human, mouse, rat, yeast,
|
|
102
|
+
*E. coli*, zebrafish, fly, *Arabidopsis*, *C. elegans*), with optional smart GO pruning.
|
|
103
|
+
- **Compute SPC Status** — score the active run against an instrument-QC baseline.
|
|
104
|
+
|
|
105
|
+
### Visualize
|
|
106
|
+
- **Volcano Plot** — log2FC vs. -log10(p), with significance threshold lines; switch the
|
|
107
|
+
significance metric, color by significance or UniProt subcellular location, and label
|
|
108
|
+
the top-N proteins independently of selection.
|
|
109
|
+
- **Heatmap** — clustered expression heatmap of the top differential proteins.
|
|
110
|
+
- **PCA** — sample-level principal-component scatter (opens in its own view).
|
|
111
|
+
- **Group-Mean Correlation** — group1 vs. group2 mean per protein, with Pearson/Spearman.
|
|
112
|
+
- **QC Dashboard** — MA plot, coefficient-of-variation, missingness matrix and an
|
|
113
|
+
intensity trend.
|
|
114
|
+
- **SPC Dashboard** — longitudinal control charts over instrument metrics
|
|
115
|
+
(median intensity, missingness, replicate correlation, protein count) with Nelson-rule
|
|
116
|
+
flagging and a Pareto of tripped rules.
|
|
117
|
+
- **Enrichment Charts** — dot plot and bar chart of the top terms, split Up/Down by
|
|
118
|
+
direction; selecting a term highlights its proteins back in the volcano.
|
|
119
|
+
|
|
120
|
+
Selecting a term in the enrichment results highlights that pathway's member proteins back
|
|
121
|
+
on the volcano — a pathway you find in the biology view is immediately located in the
|
|
122
|
+
statistics view, so the two never drift apart:
|
|
123
|
+
|
|
124
|
+

|
|
125
|
+
|
|
126
|
+

|
|
127
|
+
|
|
128
|
+
*Selecting the KEGG Cell Cycle term (top) highlights its 25 member proteins on the volcano (bottom).*
|
|
129
|
+
|
|
130
|
+
### Share
|
|
131
|
+
- **Share Analysis for Review** — publish a trimmed, read-only snapshot (table + volcano +
|
|
132
|
+
enrichment charts) to a reviewer group. The source table is never mutated; reviewer
|
|
133
|
+
access is verified (and rolled back on an over-permissive grant); the snapshot is
|
|
134
|
+
optionally re-opened and shape-checked to confirm it survives a reload; re-publishing
|
|
135
|
+
supersedes the prior version. A **Shared Analysis** context panel surfaces the
|
|
136
|
+
publication's audit trail.
|
|
137
|
+
|
|
138
|
+
## Protein annotation
|
|
139
|
+
|
|
140
|
+
Clicking a protein-ID cell opens the **UniProt** info panel, which fetches the protein
|
|
141
|
+
name, gene, organism, functional description, GO terms (MF / BP / CC) and KEGG / Reactome /
|
|
142
|
+
InterPro cross-references from the UniProt REST API and caches them in App Data.
|
|
143
|
+
|
|
144
|
+
## Semantic type detection
|
|
145
|
+
|
|
146
|
+
Columns are auto-detected and tagged so the package keeps working on tables from vendors
|
|
147
|
+
it hasn't seen — detectors match on column-name hints and validate sample values.
|
|
148
|
+
|
|
149
|
+
| Semantic type | Detects |
|
|
150
|
+
|---------------|---------|
|
|
151
|
+
| `Proteomics-ProteinId` | Protein IDs, Majority Protein IDs, UniProt, Accession (validated against the UniProt accession pattern) |
|
|
152
|
+
| `Proteomics-GeneSymbol` | Gene Names, Gene Symbol, Gene |
|
|
153
|
+
| `Proteomics-Log2FC` | columns naming "log2" with "fc"/"fold" |
|
|
154
|
+
| `Proteomics-PValue` | p-value, adj.p, FDR, q-value (range 0–1) |
|
|
155
|
+
| `Proteomics-Intensity` | Intensity, LFQ / Reporter / Razor / MaxLFQ Intensity, iBAQ |
|
|
156
|
+
| `Proteomics-SubcellularLocation` | UniProt subcellular-location strings |
|
|
157
|
+
| `Proteomics-DisplayName`, `Proteomics-SourceId` | gene-label resolver fields |
|
|
158
|
+
| `Proteomics-NumeratorMean`, `Proteomics-DenominatorMean` | per-group means in Spectronaut Candidates exports |
|
|
159
|
+
|
|
160
|
+
## Integrations & requirements
|
|
161
|
+
|
|
162
|
+
- **No credentials required.** The package calls only public REST APIs — UniProt (protein
|
|
163
|
+
annotation) and g:Profiler (enrichment).
|
|
164
|
+
- **R is optional.** `limma_de.R`, `deqms_de.R` and `vsn_normalize.R` run server-side and
|
|
165
|
+
require a configured Datagrok R compute environment; every R path has a client-side
|
|
166
|
+
TypeScript fallback, so the package is fully functional without R.
|
|
167
|
+
|
|
168
|
+
## Demo data
|
|
169
|
+
|
|
170
|
+
Example datasets ship in `files/demo/` (see its `README.md`):
|
|
171
|
+
|
|
172
|
+
- `proteinGroups.txt` — small MaxQuant example
|
|
173
|
+
- `cptac-spike-in.txt` — CPTAC UPS spike-in reference with known concentrations
|
|
174
|
+
- `fragpipe-smoke-test.tsv` — FragPipe `combined_protein.tsv` example
|
|
175
|
+
- `spectronaut-hye-candidates.tsv` — Spectronaut Candidates (pre-computed DE)
|
|
176
|
+
- `spectronaut-hye-precursor.tsv` / `spectronaut-hye-mix.tsv` — Spectronaut long-form reports
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
cd packages/Proteomics
|
|
182
|
+
|
|
183
|
+
npm run build # grok api && grok check --soft && webpack
|
|
184
|
+
grok publish local # build + publish to your configured server
|
|
185
|
+
grok link && npm install # link local datagrok-api / @datagrok-libraries
|
|
186
|
+
grok test --host localhost # run the package tests
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## See also
|
|
190
|
+
|
|
191
|
+
- [Personas & capabilities](docs/personas-and-capabilities.md) — who (analyst vs biology
|
|
192
|
+
scientist) can do what, and how the boundary is enforced.
|
|
193
|
+
- **TODO:** Datagrok Proteomics documentation — the help page at
|
|
194
|
+
`https://datagrok.ai/help/domains/bio/proteomics` does not exist yet and still needs to
|
|
195
|
+
be written.
|
package/detectors.js
CHANGED
|
@@ -1,9 +1,152 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
class ProteomicsPackageDetectors extends DG.Package {
|
|
2
|
+
//meta.role: semTypeDetector
|
|
3
|
+
//input: column col
|
|
4
|
+
//output: string semType
|
|
5
|
+
detectProteinId(col) {
|
|
6
|
+
if (col.type !== DG.TYPE.STRING)
|
|
7
|
+
return null;
|
|
8
|
+
const name = col.name.toLowerCase();
|
|
9
|
+
if (name === 'protein ids' || name === 'protein id' || name === 'majority protein ids' ||
|
|
10
|
+
name === 'primary protein id' || name === 'leading protein' || name === 'leading razor protein' ||
|
|
11
|
+
name === 'uniprot' || name === 'accession') {
|
|
12
|
+
const sample = col.toList().slice(0, 20).filter((v) => v != null);
|
|
13
|
+
const uniprotPattern = /^(?:[OPQ][0-9][A-Z0-9]{3}[0-9]|[A-NR-Z][0-9](?:[A-Z][A-Z0-9]{2}[0-9]){1,2})$/;
|
|
14
|
+
if (sample.some((v) => uniprotPattern.test(v.split(';')[0]))) {
|
|
15
|
+
col.semType = 'Proteomics-ProteinId';
|
|
16
|
+
return col.semType;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//meta.role: semTypeDetector
|
|
23
|
+
//input: column col
|
|
24
|
+
//output: string semType
|
|
25
|
+
detectGeneSymbol(col) {
|
|
26
|
+
if (col.type !== DG.TYPE.STRING)
|
|
27
|
+
return null;
|
|
28
|
+
const name = col.name.toLowerCase();
|
|
29
|
+
if (name === 'gene names' || name === 'gene name' || name === 'gene symbol' || name === 'gene') {
|
|
30
|
+
col.semType = 'Proteomics-GeneSymbol';
|
|
31
|
+
return col.semType;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//meta.role: semTypeDetector
|
|
37
|
+
//input: column col
|
|
38
|
+
//output: string semType
|
|
39
|
+
detectSubcellularLocation(col) {
|
|
40
|
+
if (col.type !== DG.TYPE.STRING)
|
|
41
|
+
return null;
|
|
42
|
+
const name = col.name.toLowerCase();
|
|
43
|
+
if (name === 'subcellular location' || name === 'subcellular location [cc]' ||
|
|
44
|
+
name === 'subcellular' || name.includes('subcellular location') || name.includes('subcellular')) {
|
|
45
|
+
col.semType = 'Proteomics-SubcellularLocation';
|
|
46
|
+
return col.semType;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//meta.role: semTypeDetector
|
|
52
|
+
//input: column col
|
|
53
|
+
//output: string semType
|
|
54
|
+
detectLog2FC(col) {
|
|
55
|
+
if (col.type !== DG.TYPE.FLOAT && col.type !== DG.TYPE.INT)
|
|
56
|
+
return null;
|
|
57
|
+
const name = col.name.toLowerCase();
|
|
58
|
+
if (name.includes('log2') && (name.includes('fc') || name.includes('fold'))) {
|
|
59
|
+
col.semType = 'Proteomics-Log2FC';
|
|
60
|
+
return col.semType;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//meta.role: semTypeDetector
|
|
66
|
+
//input: column col
|
|
67
|
+
//output: string semType
|
|
68
|
+
detectPValue(col) {
|
|
69
|
+
if (col.type !== DG.TYPE.FLOAT && col.type !== DG.TYPE.INT)
|
|
70
|
+
return null;
|
|
71
|
+
const name = col.name.toLowerCase();
|
|
72
|
+
if ((name.includes('p-value') || name.includes('pvalue') || name.includes('p.value') ||
|
|
73
|
+
name.includes('adj.p') || name.includes('fdr') || name.includes('q-value') || name.includes('qvalue')) &&
|
|
74
|
+
col.min >= 0 && col.max <= 1) {
|
|
75
|
+
col.semType = 'Proteomics-PValue';
|
|
76
|
+
return col.semType;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//meta.role: semTypeDetector
|
|
82
|
+
//input: column col
|
|
83
|
+
//output: string semType
|
|
84
|
+
detectIntensity(col) {
|
|
85
|
+
if (col.type !== DG.TYPE.FLOAT && col.type !== DG.TYPE.INT)
|
|
86
|
+
return null;
|
|
87
|
+
const name = col.name.toLowerCase();
|
|
88
|
+
const isRawIntensity = name.startsWith('intensity') || name.startsWith('lfq intensity') ||
|
|
89
|
+
name.startsWith('reporter intensity') || name.startsWith('ibaq') ||
|
|
90
|
+
name.endsWith(' maxlfq intensity') || name.endsWith(' razor intensity') ||
|
|
91
|
+
name.endsWith(' intensity');
|
|
92
|
+
const isLog2Intensity = (name.startsWith('log2(') || name.startsWith('log2 ')) &&
|
|
93
|
+
(name.includes('intensity') || name.includes('ibaq'));
|
|
94
|
+
if (isRawIntensity || isLog2Intensity) {
|
|
95
|
+
col.semType = 'Proteomics-Intensity';
|
|
96
|
+
return col.semType;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//meta.role: semTypeDetector
|
|
102
|
+
//input: column col
|
|
103
|
+
//output: string semType
|
|
104
|
+
detectDisplayName(col) {
|
|
105
|
+
if (col.type !== DG.TYPE.STRING)
|
|
106
|
+
return null;
|
|
107
|
+
if (col.name.toLowerCase() === 'display name') {
|
|
108
|
+
col.semType = 'Proteomics-DisplayName';
|
|
109
|
+
return col.semType;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
//meta.role: semTypeDetector
|
|
115
|
+
//input: column col
|
|
116
|
+
//output: string semType
|
|
117
|
+
detectSourceId(col) {
|
|
118
|
+
if (col.type !== DG.TYPE.STRING)
|
|
119
|
+
return null;
|
|
120
|
+
if (col.name.toLowerCase() === 'source id') {
|
|
121
|
+
col.semType = 'Proteomics-SourceId';
|
|
122
|
+
return col.semType;
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
//meta.role: semTypeDetector
|
|
128
|
+
//input: column col
|
|
129
|
+
//output: string semType
|
|
130
|
+
detectNumeratorMean(col) {
|
|
131
|
+
if (col.type !== DG.TYPE.FLOAT && col.type !== DG.TYPE.INT)
|
|
132
|
+
return null;
|
|
133
|
+
if (col.name.toLowerCase() === 'numerator mean') {
|
|
134
|
+
col.semType = 'Proteomics-NumeratorMean';
|
|
135
|
+
return col.semType;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
//meta.role: semTypeDetector
|
|
141
|
+
//input: column col
|
|
142
|
+
//output: string semType
|
|
143
|
+
detectDenominatorMean(col) {
|
|
144
|
+
if (col.type !== DG.TYPE.FLOAT && col.type !== DG.TYPE.INT)
|
|
145
|
+
return null;
|
|
146
|
+
if (col.name.toLowerCase() === 'denominator mean') {
|
|
147
|
+
col.semType = 'Proteomics-DenominatorMean';
|
|
148
|
+
return col.semType;
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|