@platforma-open/milaboratories.mixcr-clonotyping-2.workflow 2.0.1 → 2.1.1

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.0.1 build /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
2
+ > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.1.1 build /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
3
3
  > rm -rf dist && pl-tengo check && pl-tengo build
4
4
 
5
5
  Processing "src/aggregate-by-clonotype-key.tpl.tengo"...
@@ -1,20 +1,20 @@
1
1
 
2
- > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.0.1 test /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
2
+ > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.1.1 test /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
3
3
  > vitest
4
4
 
5
5
 
6
6
   RUN  v2.1.8 /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
7
7
 
8
- ✓ src/test/columns.test.ts (6 tests) 47946ms
9
- ✓ checking preset for 'milab-human-dna-xcr-7genes-multiplex' 11920ms
10
- ✓ checking preset for '10x-sc-xcr-vdj' 7407ms
11
- ✓ checking preset for 'cellecta-human-rna-xcr-umi-drivermap-…' 7323ms
12
- ✓ checking preset for 'takara-human-rna-bcr-umi-smartseq' 7314ms
13
- ✓ checking preset for 'rna-seq' 6897ms
14
- ✓ checking preset for 'generic-single-cell-gex' 7083ms
8
+ ✓ src/test/columns.test.ts (6 tests) 49169ms
9
+ ✓ checking preset for 'milab-human-dna-xcr-7genes-multiplex' 13728ms
10
+ ✓ checking preset for '10x-sc-xcr-vdj' 7394ms
11
+ ✓ checking preset for 'cellecta-human-rna-xcr-umi-drivermap-…' 7337ms
12
+ ✓ checking preset for 'takara-human-rna-bcr-umi-smartseq' 7115ms
13
+ ✓ checking preset for 'rna-seq' 6700ms
14
+ ✓ checking preset for 'generic-single-cell-gex' 6894ms
15
15
 
16
16
   Test Files  1 passed (1)
17
17
   Tests  6 passed (6)
18
-  Start at  11:38:19
19
-  Duration  48.72s (transform 43ms, setup 0ms, collect 544ms, tests 47.95s, environment 0ms, prepare 72ms)
18
+  Start at  18:50:45
19
+  Duration  49.93s (transform 43ms, setup 0ms, collect 537ms, tests 49.17s, environment 0ms, prepare 56ms)
20
20
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @platforma-open/milaboratories.mixcr-clonotyping.workflow
2
2
 
3
+ ## 2.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - aed9be8: Fixes trace information propagation
8
+ Enhances export specifications by adding block and segment annotations
9
+ Updates abundance labels
10
+ Refines chain names in the model
11
+
12
+ ## 2.1.0
13
+
14
+ ### Minor Changes
15
+
16
+ - a168fe3: pl7.app/abundance/isPrimary and pl7.app/isAnchor annotations added to the output columns
17
+
3
18
  ## 2.0.1
4
19
 
5
20
  ### Patch Changes
@@ -1,4 +1,5 @@
1
1
  maps := import("@platforma-sdk/workflow-tengo:maps")
2
+ slices := import("@platforma-sdk/workflow-tengo:slices")
2
3
  ll := import("@platforma-sdk/workflow-tengo:ll")
3
4
  text := import("text")
4
5
  json := import("json")
@@ -118,6 +119,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
118
119
  "pl7.app/isAbundance": "true",
119
120
  "pl7.app/abundance/unit": "reads",
120
121
  "pl7.app/abundance/normalized": "false",
122
+ "pl7.app/abundance/isPrimary": !hasUmi ? "true" : undefined,
123
+ "pl7.app/isAnchor": !hasUmi ? "true" : undefined,
121
124
  "pl7.app/label": "Number Of Reads"
122
125
  })
123
126
  }
@@ -134,6 +137,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
134
137
  "pl7.app/isAbundance": "true",
135
138
  "pl7.app/abundance/unit": "reads",
136
139
  "pl7.app/abundance/normalized": "true",
140
+ "pl7.app/abundance/isPrimary": !hasUmi ? "true" : undefined,
137
141
  "pl7.app/label": "Fraction of reads"
138
142
  })
139
143
  }
@@ -157,7 +161,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
157
161
  "pl7.app/isAbundance": "true",
158
162
  "pl7.app/abundance/unit": "molecules",
159
163
  "pl7.app/abundance/normalized": "false",
160
- "pl7.app/label": "Number of UMI"
164
+ "pl7.app/abundance/isPrimary": "true",
165
+ "pl7.app/isAnchor": "true",
166
+ "pl7.app/label": "Number of UMIs"
161
167
  })
162
168
  }
163
169
  }, {
@@ -173,7 +179,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
173
179
  "pl7.app/isAbundance": "true",
174
180
  "pl7.app/abundance/unit": "molecules",
175
181
  "pl7.app/abundance/normalized": "true",
176
- "pl7.app/label": "Fraction of UMI"
182
+ "pl7.app/abundance/isPrimary": "true",
183
+ "pl7.app/label": "Fraction of UMIs"
177
184
  })
178
185
  }
179
186
  } ]
@@ -229,13 +236,19 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
229
236
 
230
237
 
231
238
 
239
+
240
+ anchorFeature := undefined;
241
+
232
242
  features := undefined
233
243
  if is_undefined(assemblingFeature) {
234
244
  features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
245
+ anchorFeature = "CDR3"
235
246
  } else if assemblingFeature != "CDR3" {
236
247
  features = [assemblingFeature, "CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
248
+ anchorFeature = assemblingFeature
237
249
  } else {
238
250
  features = ["CDR3"]
251
+ anchorFeature = "CDR3"
239
252
  }
240
253
 
241
254
  for isImputed in ( is_undefined(assemblingFeature) ? [false, true] : [false] ) {
@@ -450,6 +463,32 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
450
463
 
451
464
 
452
465
 
466
+
467
+
468
+ addSpec := func(columns, additionalSpec) {
469
+ return slices.map(columns, func(columnSpec) {
470
+ return maps.deepMerge(columnSpec, additionalSpec)
471
+ })
472
+ }
473
+
474
+ columnsSpecPerSample = addSpec(columnsSpecPerSample, { spec: { domain: {
475
+ "pl7.app/blockId": blockId
476
+ } } })
477
+
478
+
479
+
480
+
481
+
482
+
483
+ columnsSpecPerClonotype = addSpec(columnsSpecPerClonotype, { spec: {
484
+ domain: {
485
+ "pl7.app/blockId": blockId
486
+ },
487
+ annotations: {
488
+ "pl7.app/segmentedBy": string(json.encode(["pl7.app/blockId"]))
489
+ }
490
+ } })
491
+
453
492
  columnsSpec := columnsSpecPerSample + columnsSpecPerClonotype
454
493
 
455
494
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-open/milaboratories.mixcr-clonotyping-2.workflow",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Tengo-based template",
5
5
  "dependencies": {
6
6
  "@platforma-open/milaboratories.mixcr-clonotyping-2.sc-clonotype-builder": "1.0.1"
@@ -9,16 +9,17 @@
9
9
  "@platforma-sdk/tengo-builder": "^1.19.2",
10
10
  "@platforma-sdk/workflow-tengo": "^2.15.6",
11
11
  "@milaboratories/software-pframes-conv": "2.1.16",
12
- "@platforma-open/milaboratories.software-small-binaries": "^1.15.15",
12
+ "@platforma-open/milaboratories.software-small-binaries": "^1.15.16",
13
13
  "@platforma-open/milaboratories.software-mixcr": "4.7.0-147-develop",
14
14
  "@platforma-open/milaboratories.software-ptransform": "^1.3.1",
15
- "@platforma-sdk/test": "^1.22.87",
15
+ "@platforma-sdk/test": "^1.22.100",
16
16
  "vitest": "^2.1.8",
17
17
  "typescript": "~5.5.4"
18
18
  },
19
19
  "scripts": {
20
20
  "build": "rm -rf dist && pl-tengo check && pl-tengo build",
21
21
  "format": "/usr/bin/env emacs --script ./format.el",
22
- "test": "vitest"
22
+ "test": "vitest",
23
+ "do-pack": "rm -f *.tgz && pnpm pack && mv *.tgz package.tgz"
23
24
  }
24
25
  }
@@ -1,4 +1,5 @@
1
1
  maps := import("@platforma-sdk/workflow-tengo:maps")
2
+ slices := import("@platforma-sdk/workflow-tengo:slices")
2
3
  ll := import("@platforma-sdk/workflow-tengo:ll")
3
4
  text := import("text")
4
5
  json := import("json")
@@ -118,6 +119,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
118
119
  "pl7.app/isAbundance": "true",
119
120
  "pl7.app/abundance/unit": "reads",
120
121
  "pl7.app/abundance/normalized": "false",
122
+ "pl7.app/abundance/isPrimary": !hasUmi ? "true" : undefined,
123
+ "pl7.app/isAnchor": !hasUmi ? "true" : undefined,
121
124
  "pl7.app/label": "Number Of Reads"
122
125
  })
123
126
  }
@@ -134,6 +137,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
134
137
  "pl7.app/isAbundance": "true",
135
138
  "pl7.app/abundance/unit": "reads",
136
139
  "pl7.app/abundance/normalized": "true",
140
+ "pl7.app/abundance/isPrimary": !hasUmi ? "true" : undefined,
137
141
  "pl7.app/label": "Fraction of reads"
138
142
  })
139
143
  }
@@ -157,7 +161,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
157
161
  "pl7.app/isAbundance": "true",
158
162
  "pl7.app/abundance/unit": "molecules",
159
163
  "pl7.app/abundance/normalized": "false",
160
- "pl7.app/label": "Number of UMI"
164
+ "pl7.app/abundance/isPrimary": "true",
165
+ "pl7.app/isAnchor": "true",
166
+ "pl7.app/label": "Number of UMIs"
161
167
  })
162
168
  }
163
169
  }, {
@@ -173,7 +179,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
173
179
  "pl7.app/isAbundance": "true",
174
180
  "pl7.app/abundance/unit": "molecules",
175
181
  "pl7.app/abundance/normalized": "true",
176
- "pl7.app/label": "Fraction of UMI"
182
+ "pl7.app/abundance/isPrimary": "true",
183
+ "pl7.app/label": "Fraction of UMIs"
177
184
  })
178
185
  }
179
186
  } ]
@@ -229,13 +236,19 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
229
236
 
230
237
  // Sequences
231
238
 
239
+ // column with nucleotide sequence of this feature will be marked as anchor
240
+ anchorFeature := undefined;
241
+
232
242
  features := undefined
233
243
  if is_undefined(assemblingFeature) {
234
244
  features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
245
+ anchorFeature = "CDR3"
235
246
  } else if assemblingFeature != "CDR3" {
236
247
  features = [assemblingFeature, "CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
248
+ anchorFeature = assemblingFeature
237
249
  } else {
238
250
  features = ["CDR3"]
251
+ anchorFeature = "CDR3"
239
252
  }
240
253
 
241
254
  for isImputed in ( is_undefined(assemblingFeature) ? [false, true] : [false] ) {
@@ -450,6 +463,32 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
450
463
 
451
464
  // All columns are added
452
465
 
466
+ // Adding block and segment annotations
467
+
468
+ addSpec := func(columns, additionalSpec) {
469
+ return slices.map(columns, func(columnSpec) {
470
+ return maps.deepMerge(columnSpec, additionalSpec)
471
+ })
472
+ }
473
+
474
+ columnsSpecPerSample = addSpec(columnsSpecPerSample, { spec: { domain: {
475
+ "pl7.app/blockId": blockId
476
+ } } })
477
+
478
+ // "pl7.app/segmentedBy" annotation indicates columns that can be meaningfully merged across
479
+ // different runs (given they have the same name and axes signature).
480
+ // Its absence indicates that merging would be semantically meaningless (e.g., abundance
481
+ // measurements specific to each analysis)
482
+
483
+ columnsSpecPerClonotype = addSpec(columnsSpecPerClonotype, { spec: {
484
+ domain: {
485
+ "pl7.app/blockId": blockId
486
+ },
487
+ annotations: {
488
+ "pl7.app/segmentedBy": string(json.encode(["pl7.app/blockId"]))
489
+ }
490
+ } })
491
+
453
492
  columnsSpec := columnsSpecPerSample + columnsSpecPerClonotype
454
493
 
455
494
  // Creating a column map for fast search
@@ -20,7 +20,7 @@ processTpl := assets.importTemplate(":process")
20
20
  wf.setPreRun(assets.importTemplate(":prerun"))
21
21
 
22
22
  wf.prepare(func(args){
23
- return{
23
+ return {
24
24
  resolvedLibraryInput: wf.resolve(args.inputLibrary, { errIfMissing: false })
25
25
  }
26
26
  })
@@ -93,7 +93,10 @@ wf.body(func(args) {
93
93
  presetSpecForBack := presetInfoResult.output("presetSpecForBack", 24 * 60 * 60 * 1000)
94
94
 
95
95
  // calculating chains
96
- chains := ["IGHeavy", "IGLight", "TRA", "TRB", "TRD", "TRG"]
96
+ chains := ["IGHeavy", "IGLight", "TRAlpha", "TRBeta", "TRGamma", "TRDelta"]
97
+ if !is_undefined(args.chains) {
98
+ chains = args.chains
99
+ }
97
100
 
98
101
  runMixcr := render.createEphemeral(processTpl, {
99
102
  inputSpec: input.getFutureInputField("spec"),
@@ -23,6 +23,7 @@ self.body(func(inputs) {
23
23
  // Exporting clones from clns file
24
24
 
25
25
  mixcrCmdBuilder := exec.builder().
26
+ inMediumQueue().
26
27
  printErrStreamToStdout().
27
28
  software(mixcrSw).
28
29
  secret("MI_LICENSE", "MI_LICENSE").
@@ -32,16 +32,17 @@ self.awaitState("presetContent", "ResourceReady")
32
32
  chainInfos := {
33
33
  "IGHeavy": { mixcrFilter: "IGH", name: "IG Heavy" },
34
34
  "IGLight": { mixcrFilter: "IGK,IGL", name: "IG Light" },
35
- "TRA": { mixcrFilter: "TRA", name: "TRA" },
36
- "TRB": { mixcrFilter: "TRB", name: "TRB" },
37
- "TRD": { mixcrFilter: "TRD", name: "TRD" },
38
- "TRG": { mixcrFilter: "TRG", name: "TRG" }
35
+ "TRAlpha": { mixcrFilter: "TRA", name: "TR Alpha" },
36
+ "TRBeta": { mixcrFilter: "TRB", name: "TR Beta" },
37
+ "TRGamma": { mixcrFilter: "TRD", name: "TR Gamma" },
38
+ "TRDelta": { mixcrFilter: "TRG", name: "TR Delta" }
39
39
  }
40
40
 
41
+ // TODO better naming
41
42
  receptorInfo := {
42
43
  "IG": { chains: ["IGHeavy", "IGLight"], name: "IG" },
43
- "TRAB": { chains: ["TRB", "TRA"], name: "TRAB" },
44
- "TRGD": { chains: ["TRD", "TRG"], name: "TRGD" }
44
+ "TRAB": { chains: ["TRAlpha", "TRBeta"], name: "TRAB" },
45
+ "TRGD": { chains: ["TRGamma", "TRDelta"], name: "TRGD" }
45
46
  }
46
47
 
47
48
  self.body(func(inputs) {
@@ -214,6 +215,7 @@ self.body(func(inputs) {
214
215
  name: "pl7.app/sequencing/readIndex",
215
216
  optional: true
216
217
  }],
218
+
217
219
  // resulting aggregation axes names will be checked against supported combinations
218
220
  // in the body template
219
221
  passAggregationAxesNames: true,
@@ -242,6 +244,7 @@ self.body(func(inputs) {
242
244
 
243
245
  for chain in chains {
244
246
  chainInfo := chainInfos[chain]
247
+ ll.assert(!is_undefined(chainInfo), "chainInfo not found for chain %v", chain)
245
248
  additionalSpec := {
246
249
  spec: {
247
250
  domain: {