@platforma-open/milaboratories.tcrdisco-enrichment.workflow 1.1.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.
@@ -0,0 +1,226 @@
1
+ self := import("@platforma-sdk/workflow-tengo:tpl")
2
+ exec := import("@platforma-sdk/workflow-tengo:exec")
3
+ assets := import("@platforma-sdk/workflow-tengo:assets")
4
+ pt := import("@platforma-sdk/workflow-tengo:pt")
5
+ xsv := import("@platforma-sdk/workflow-tengo:pframes.xsv")
6
+ pframes := import("@platforma-sdk/workflow-tengo:pframes")
7
+ pSpec := import("@platforma-sdk/workflow-tengo:pframes.spec")
8
+ smart := import("@platforma-sdk/workflow-tengo:smart")
9
+ text := import("text")
10
+ json := import("json")
11
+
12
+ subsetAssignment := assets.importSoftware("@platforma-open/milaboratories.run-tcrdisco-enrichment.software:subset-assignment")
13
+ diffSoftware := assets.importSoftware("@platforma-open/milaboratories.run-tcrdisco-enrichment.software:tcr-disco")
14
+ getEnrichedFrequenciesSoftware := assets.importSoftware("@platforma-open/milaboratories.run-tcrdisco-enrichment.software:get-enriched-frequencies")
15
+ tcrdiscoDaPfconvParamsLib := import(":libs.tcrdisco_da_pfconv_params")
16
+ self.validateInputs({
17
+ "__options__,closed": "",
18
+ "numerators": "any",
19
+ "denominators": "any",
20
+ "mainAlphaTsv": "any",
21
+ "mainBetaTsv": "any",
22
+ "metadataTsv": "any",
23
+ "cdAlphaTsv,?": "any",
24
+ "cdBetaTsv,?": "any",
25
+ "cdMetadataTsv,?": "any",
26
+ "cdSubsetCol,?": "string",
27
+ "covariatesTsv": "any",
28
+ "contrastColLabel": "string",
29
+ "thresholdCounts": "number",
30
+ "thresholdSamples": "number",
31
+ "log2FcThreshold": "number",
32
+ "pAdjThreshold": "number",
33
+ "mainAlphaSpec,?": "any",
34
+ "mainBetaSpec,?": "any",
35
+ "blockId,?": "string",
36
+ "defaultConvMem,?": "string",
37
+ "defaultConvCpu,?": "number"
38
+ })
39
+
40
+ self.defineOutputs("topTableFileAlpha","topTableFileBeta","daFileAlpha",
41
+ "daFileBeta","contrastMap","mainAlphaFrequenciesTsv","mainBetaFrequenciesTsv",
42
+ "clonotypeToSubsetAlpha","clonotypeToSubsetBeta",
43
+ "robustEnrichmentPFAlpha_clonotype","robustEnrichmentPFBeta_clonotype")
44
+
45
+ self.body(func(inputs) {
46
+
47
+ denominators := inputs.denominators
48
+ denominatorString := text.join(denominators, "-")
49
+ covariatesTsv := inputs.covariatesTsv
50
+ contrastColLabel := inputs.contrastColLabel
51
+ thresholdCounts := inputs.thresholdCounts
52
+ thresholdSamples := inputs.thresholdSamples
53
+ log2FcThreshold := inputs.log2FcThreshold
54
+ pAdjThreshold := inputs.pAdjThreshold
55
+
56
+ mainAlphaTsv := undefined
57
+ mainBetaTsv := undefined
58
+ // Assign CD4/CD8 subsets to main data and QC the input files
59
+ builder := exec.builder().
60
+ software(subsetAssignment).
61
+ addFile("mainAlpha.tsv", inputs.mainAlphaTsv).
62
+ addFile("mainBeta.tsv", inputs.mainBetaTsv).
63
+ addFile("metadata.tsv", inputs.metadataTsv).
64
+ arg("--main_alpha").arg("mainAlpha.tsv").
65
+ arg("--main_beta").arg("mainBeta.tsv").
66
+ arg("--metadata").arg("metadata.tsv").
67
+ arg("-o").arg(".").
68
+ saveFile("main_alpha_table.tsv").
69
+ saveFile("main_beta_table.tsv")
70
+ if !is_undefined(inputs.cdAlphaTsv) && !is_undefined(inputs.cdBetaTsv) {
71
+ builder.
72
+ addFile("cdAlpha.tsv", inputs.cdAlphaTsv).
73
+ addFile("cdBeta.tsv", inputs.cdBetaTsv).
74
+ arg("--cd_alpha").arg("cdAlpha.tsv").
75
+ arg("--cd_beta").arg("cdBeta.tsv").
76
+ arg("--cd_subset_col").arg(inputs.cdSubsetCol)
77
+ }
78
+ builder = builder.run()
79
+
80
+ // Stored main tables with/out subset information and after QC for samples
81
+ // with both alpha and beta chains (we keep only the most frequent one)
82
+ mainAlphaTsv = builder.getFile("main_alpha_table.tsv")
83
+ mainBetaTsv = builder.getFile("main_beta_table.tsv")
84
+
85
+ // run differential analysis per numerator
86
+ wf := pt.workflow().cpu(1).mem("2GiB")
87
+ dfsDegAlpha := []
88
+ dfsDegBeta := []
89
+ dfsTopTableAlpha := []
90
+ dfsTopTableBeta := []
91
+ contrastMap := {}
92
+
93
+ // Format 2 specs (with contrast in domain) - process outside workflow
94
+ degPframeBuilderAlpha_clonotype := pframes.pFrameBuilder()
95
+ degPframeBuilderBeta_clonotype := pframes.pFrameBuilder()
96
+ regDirPframeBuilderAlpha_clonotype := pframes.pFrameBuilder()
97
+ regDirPframeBuilderBeta_clonotype := pframes.pFrameBuilder()
98
+ robustEnrichmentPframeBuilderAlpha_clonotype := pframes.pFrameBuilder()
99
+ robustEnrichmentPframeBuilderBeta_clonotype := pframes.pFrameBuilder()
100
+
101
+ // Create trace if specs are provided
102
+ trace := undefined
103
+ if !is_undefined(inputs.mainAlphaSpec) {
104
+ trace = pSpec.makeTrace(inputs.mainAlphaSpec,
105
+ {type: "milaboratories.tcr-disco-enrichment", importance: 30,
106
+ label: "DA - Denominator: " + denominatorString + " (log2FC: " + log2FcThreshold + ", pAdj: " + pAdjThreshold + ")"}
107
+ )
108
+ }
109
+
110
+ diffExec := exec.builder().
111
+ software(diffSoftware).
112
+ addFile("mainAlpha.tsv", mainAlphaTsv).
113
+ addFile("mainBeta.tsv", mainBetaTsv).
114
+ addFile("covariates.tsv", covariatesTsv).
115
+ arg("--main_alpha").arg("mainAlpha.tsv").
116
+ arg("--main_beta").arg("mainBeta.tsv").
117
+ arg("--covariates").arg("covariates.tsv").
118
+ arg("-t").arg(contrastColLabel).
119
+ arg("-n").arg(string(json.encode(inputs.numerators))).
120
+ arg("-d").arg(string(json.encode(denominators))).
121
+ arg("-f").arg(string(log2FcThreshold)).
122
+ arg("-p").arg(string(pAdjThreshold)).
123
+ arg("--threshold_counts").arg(string(thresholdCounts)).
124
+ arg("-s").arg(string(thresholdSamples)).
125
+ arg("-o").arg(".").
126
+ saveFile("DA_alpha.csv").
127
+ saveFile("topTable_alpha.csv").
128
+ saveFile("DA_beta.csv").
129
+ saveFile("topTable_beta.csv")
130
+
131
+ for numerator in inputs.numerators {
132
+ numerator = string(numerator)
133
+ contrastMap[numerator + " vs " + denominatorString] = numerator + " vs " + denominatorString
134
+
135
+ diffExec.saveFile("robust_enrichment_alpha_" + numerator + ".csv").
136
+ saveFile("robust_enrichment_beta_" + numerator + ".csv")
137
+ }
138
+ diffExec = diffExec.run()
139
+
140
+ // Process format 2 specs (with contrast in domain) if specs are provided
141
+ // Delete this part once filters in tcr-leads allow axis value selection
142
+ for numerator in inputs.numerators {
143
+ numerator = string(numerator)
144
+ if !is_undefined(inputs.mainAlphaSpec) {
145
+ comparison := numerator + " - vs - " + denominatorString
146
+ defaultConvMem := inputs.defaultConvMem
147
+ if defaultConvMem == undefined {
148
+ defaultConvMem = "16GiB"
149
+ }
150
+ defaultConvCpu := inputs.defaultConvCpu
151
+ if defaultConvCpu == undefined {
152
+ defaultConvCpu = 1
153
+ }
154
+
155
+ // Process alpha chain
156
+ degImportParams := tcrdiscoDaPfconvParamsLib.getColumns(inputs.mainAlphaSpec, inputs.cdSubsetCol, numerator, comparison)
157
+ degPfAlpha := xsv.importFile(diffExec.getFile("robust_enrichment_alpha_" + numerator + ".csv"), "csv", degImportParams, {mem: defaultConvMem, cpu: defaultConvCpu})
158
+
159
+ // We just export robust enrichment for now, that will have a unique value per clonotype
160
+ robustEnrichmentPframeBuilderAlpha_clonotype.add(
161
+ numerator,
162
+ trace.inject(degPfAlpha["robustEnrichment.spec"]),
163
+ degPfAlpha["robustEnrichment.data"]
164
+ )
165
+
166
+ // Process beta chain if available
167
+ if !is_undefined(inputs.mainBetaSpec) {
168
+ degImportParamsBeta := tcrdiscoDaPfconvParamsLib.getColumns(inputs.mainBetaSpec, inputs.cdSubsetCol, numerator, comparison)
169
+ degPfBeta := xsv.importFile(diffExec.getFile("robust_enrichment_beta_" + numerator + ".csv"), "csv", degImportParamsBeta, {mem: defaultConvMem, cpu: defaultConvCpu})
170
+
171
+ /// We just export robust enrichment for now, that will have a unique value per clonotype
172
+ robustEnrichmentPframeBuilderBeta_clonotype.add(
173
+ numerator,
174
+ trace.inject(degPfBeta["robustEnrichment.spec"]),
175
+ degPfBeta["robustEnrichment.data"]
176
+ )
177
+ }
178
+ }
179
+ }
180
+
181
+ getEnrichedFrequenciesExec := exec.builder().
182
+ software(getEnrichedFrequenciesSoftware).
183
+ addFile("mainAlpha.tsv", mainAlphaTsv).
184
+ addFile("mainBeta.tsv", mainBetaTsv).
185
+ addFile("DA_alpha.csv", diffExec.getFile("DA_alpha.csv")).
186
+ addFile("DA_beta.csv", diffExec.getFile("DA_beta.csv")).
187
+ arg("--main_alpha").arg("mainAlpha.tsv").
188
+ arg("--main_beta").arg("mainBeta.tsv").
189
+ arg("--da_alpha").arg("DA_alpha.csv").
190
+ arg("--da_beta").arg("DA_beta.csv").
191
+ arg("-o").arg(".").
192
+ saveFile("main_alpha_frequencies.tsv").
193
+ saveFile("main_beta_frequencies.tsv").
194
+ saveFile("clonotype_to_subset_alpha.tsv").
195
+ saveFile("clonotype_to_subset_beta.tsv").
196
+ run()
197
+ mainAlphaFrequenciesTsv := getEnrichedFrequenciesExec.getFile("main_alpha_frequencies.tsv")
198
+ mainBetaFrequenciesTsv := getEnrichedFrequenciesExec.getFile("main_beta_frequencies.tsv")
199
+ clonotypeToSubsetAlpha := getEnrichedFrequenciesExec.getFile("clonotype_to_subset_alpha.tsv")
200
+ clonotypeToSubsetBeta := getEnrichedFrequenciesExec.getFile("clonotype_to_subset_beta.tsv")
201
+
202
+ // Build format 2 PFrames
203
+ robustEnrichmentPFAlpha_clonotype := undefined
204
+ robustEnrichmentPFBeta_clonotype := undefined
205
+ if !is_undefined(inputs.mainAlphaSpec) {
206
+ robustEnrichmentPFAlpha_clonotype = robustEnrichmentPframeBuilderAlpha_clonotype.build()
207
+ if !is_undefined(inputs.mainBetaSpec) {
208
+ robustEnrichmentPFBeta_clonotype = robustEnrichmentPframeBuilderBeta_clonotype.build()
209
+ }
210
+ }
211
+
212
+ return {
213
+ topTableFileAlpha: diffExec.getFile("topTable_alpha.csv"),
214
+ topTableFileBeta: diffExec.getFile("topTable_beta.csv"),
215
+ daFileAlpha: diffExec.getFile("DA_alpha.csv"),
216
+ daFileBeta: diffExec.getFile("DA_beta.csv"),
217
+ contrastMap: contrastMap,
218
+ mainAlphaFrequenciesTsv: mainAlphaFrequenciesTsv,
219
+ mainBetaFrequenciesTsv: mainBetaFrequenciesTsv,
220
+ clonotypeToSubsetAlpha: clonotypeToSubsetAlpha,
221
+ clonotypeToSubsetBeta: clonotypeToSubsetBeta,
222
+ robustEnrichmentPFAlpha_clonotype: robustEnrichmentPFAlpha_clonotype,
223
+ robustEnrichmentPFBeta_clonotype: robustEnrichmentPFBeta_clonotype
224
+ }
225
+ })
226
+
package/src/wf.test.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { tplTest } from "@platforma-sdk/test";
2
+
3
+ tplTest(
4
+ 'should return a concatenated string',
5
+ async ({ helper, expect }) => {
6
+ const results = await helper.renderWorkflow("main", false, {
7
+ name: 'World'
8
+ });
9
+
10
+ const tengoMessage = results.output("tengoMessage", (a) => a?.getDataAsJson<string>());
11
+ expect(await tengoMessage.awaitStableValue()).eq('Hello from Tengo, World!');
12
+ }
13
+ );
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "commonjs",
5
+ "moduleResolution": "node",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "sourceMap": true,
11
+ "declaration": true
12
+ },
13
+ "types": [],
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ watch: false,
6
+ maxConcurrency: 3,
7
+ testTimeout: 5000
8
+ }
9
+ });