@platforma-open/milaboratories.mixcr-clonotyping-2.workflow 2.8.2 → 2.10.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.
@@ -1,6 +1,6 @@
1
1
   WARN  Issue while reading "/home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.8.2 build /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
3
+ > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.10.0 build /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
4
4
  > rm -rf dist && pl-tengo check && pl-tengo build
5
5
 
6
6
  info: Skipping unknown file type: test/columns.test.ts
@@ -1,21 +1,21 @@
1
1
   WARN  Issue while reading "/home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.8.2 test /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
3
+ > @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.10.0 test /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
4
4
  > vitest
5
5
 
6
6
 
7
7
   RUN  v2.1.8 /home/runner/work/mixcr-clonotyping-2/mixcr-clonotyping-2/workflow
8
8
 
9
- ✓ src/test/columns.test.ts (6 tests) 53957ms
10
- ✓ checking preset for 'milab-human-dna-xcr-7genes-multiplex' 12559ms
11
- ✓ checking preset for '10x-sc-xcr-vdj' 8530ms
12
- ✓ checking preset for 'cellecta-human-rna-xcr-umi-drivermap-…' 8433ms
13
- ✓ checking preset for 'takara-human-rna-bcr-umi-smartseq' 8412ms
14
- ✓ checking preset for 'rna-seq' 8008ms
15
- ✓ checking preset for 'generic-single-cell-gex' 8014ms
9
+ ✓ src/test/columns.test.ts (6 tests) 54411ms
10
+ ✓ checking preset for 'milab-human-dna-xcr-7genes-multiplex' 12674ms
11
+ ✓ checking preset for '10x-sc-xcr-vdj' 8775ms
12
+ ✓ checking preset for 'cellecta-human-rna-xcr-umi-drivermap-…' 8518ms
13
+ ✓ checking preset for 'takara-human-rna-bcr-umi-smartseq' 8439ms
14
+ ✓ checking preset for 'rna-seq' 8026ms
15
+ ✓ checking preset for 'generic-single-cell-gex' 7977ms
16
16
 
17
17
   Test Files  1 passed (1)
18
18
   Tests  6 passed (6)
19
-  Start at  16:34:49
20
-  Duration  54.77s (transform 44ms, setup 0ms, collect 587ms, tests 53.96s, environment 0ms, prepare 62ms)
19
+  Start at  14:49:37
20
+  Duration  55.34s (transform 57ms, setup 0ms, collect 660ms, tests 54.41s, environment 0ms, prepare 68ms)
21
21
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @platforma-open/milaboratories.mixcr-clonotyping.workflow
2
2
 
3
+ ## 2.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b334fd0: Aggregated column "Number Of Samples" added to per-clonotype output
8
+ Exported clonotypes are limited only to productive & full-receptor
9
+
10
+ ## 2.9.0
11
+
12
+ ### Minor Changes
13
+
14
+ - 1de5b81: MiXCR upgrade to increase export process memory
15
+
3
16
  ## 2.8.2
4
17
 
5
18
  ### Patch Changes
@@ -121,6 +121,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
121
121
  columnsSpecPerSample := []
122
122
  columnsSpecPerSampleSc := undefined
123
123
  columnsSpecPerClonotype := []
124
+ columnsSpecPerClonotypeSc := undefined
124
125
 
125
126
 
126
127
  exportArgs := []
@@ -211,6 +212,23 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
211
212
  mainAbundanceColumn = "uniqueMoleculeFraction"
212
213
  }
213
214
 
215
+ sampleCountColumn := {
216
+ column: "sampleCount",
217
+ id: "sample-count",
218
+ allowNA: false,
219
+ spec: {
220
+ name: "pl7.app/vdj/sampleCount",
221
+ valueType: "Int",
222
+ annotations: a(87110, true, {
223
+ "pl7.app/min": "1",
224
+ "pl7.app/isAbundance": "true",
225
+ "pl7.app/abundance/unit": "samples",
226
+ "pl7.app/abundance/normalized": "false",
227
+ "pl7.app/label": "Number of Samples"
228
+ })
229
+ }
230
+ }
231
+
214
232
  if isSingleCell {
215
233
 
216
234
  columnsSpecPerSample = addSpec(columnsSpecPerSample, {
@@ -247,6 +265,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
247
265
  valueType: "Double",
248
266
  annotations: a(20000, false, {
249
267
  "pl7.app/min": "0",
268
+ "pl7.app/max": "1",
250
269
  "pl7.app/isAbundance": "true",
251
270
  "pl7.app/abundance/unit": "cells",
252
271
  "pl7.app/abundance/normalized": "true",
@@ -255,6 +274,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
255
274
  })
256
275
  }
257
276
  } ]
277
+ columnsSpecPerClonotypeSc = [ sampleCountColumn ]
278
+ } else {
279
+ columnsSpecPerClonotype += [ sampleCountColumn ]
258
280
  }
259
281
 
260
282
  orderP := 80000
@@ -478,6 +500,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
478
500
 
479
501
 
480
502
  ]
503
+ mainProductiveColumn := flagColumnVariants[0].columnPrefix + productiveFeature
504
+ mainProductiveArgs := [ flagColumnVariants[0].arg, productiveFeature ]
481
505
  for variant in flagColumnVariants {
482
506
  columnsSpecPerClonotype += [ {
483
507
  column: variant.columnPrefix + productiveFeature,
@@ -658,10 +682,13 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
658
682
  columnsSpecPerSample: columnsSpecPerSample,
659
683
  columnsSpecPerSampleSc: columnsSpecPerSampleSc,
660
684
  columnsSpecPerClonotype: columnsSpecPerClonotype,
685
+ columnsSpecPerClonotypeSc: columnsSpecPerClonotypeSc,
661
686
 
662
687
  columnsSpec: columnsSpec,
663
688
 
664
689
  mainAbundanceColumn: mainAbundanceColumn,
690
+ mainProductiveColumn: mainProductiveColumn,
691
+ mainProductiveArgs: mainProductiveArgs,
665
692
 
666
693
  exportArgs: exportArgs
667
694
  }
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.8.2",
3
+ "version": "2.10.0",
4
4
  "description": "Tengo-based template",
5
5
  "dependencies": {
6
6
  "@platforma-sdk/workflow-tengo": "^4.0.8",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "devDependencies": {
10
10
  "@platforma-sdk/tengo-builder": "^2.0.3",
11
- "@platforma-open/milaboratories.software-mixcr": "4.7.0-149-develop",
11
+ "@platforma-open/milaboratories.software-mixcr": "4.7.0-150-develop",
12
12
  "@platforma-open/milaboratories.software-ptransform": "^1.3.1",
13
13
  "@platforma-sdk/test": "^1.29.3",
14
14
  "vitest": "^2.1.8",
@@ -4,6 +4,7 @@ pConstants := import("@platforma-sdk/workflow-tengo:pframes.constants")
4
4
  slices := import("@platforma-sdk/workflow-tengo:slices")
5
5
  assets := import("@platforma-sdk/workflow-tengo:assets")
6
6
  exec := import("@platforma-sdk/workflow-tengo:exec")
7
+ maps := import("@platforma-sdk/workflow-tengo:maps")
7
8
 
8
9
  json := import("json")
9
10
 
@@ -21,6 +22,14 @@ self.body(func(inputs) {
21
22
  mainAbundanceColumn := params.mainAbundanceColumn
22
23
  clonotypeColumns := params.clonotypeColumns
23
24
 
25
+ pickCols := []
26
+ for col in clonotypeColumns {
27
+ if col == "sampleCount" {
28
+ continue
29
+ }
30
+ pickCols = append(pickCols, [col, col])
31
+ }
32
+
24
33
  // Adding clonotypeKey column
25
34
  pWorkflow := {
26
35
  steps: [ {
@@ -29,9 +38,11 @@ self.body(func(inputs) {
29
38
  aggregations: [ {
30
39
  type: "max_by",
31
40
  rankingCol: mainAbundanceColumn,
32
- pickCols: slices.map(clonotypeColumns, func(col) {
33
- return [col, col]
34
- })
41
+ pickCols: pickCols
42
+ }, {
43
+ type: "count",
44
+ src: mainAbundanceColumn,
45
+ dst: "sampleCount"
35
46
  } ]
36
47
  } ]
37
48
  }
@@ -42,7 +53,9 @@ self.body(func(inputs) {
42
53
  arg("--workflow").arg("wf.json").
43
54
  writeFile("wf.json", json.encode(pWorkflow))
44
55
 
45
- for sKey, inputFile in inputData.inputs() {
56
+ inputMap := inputData.inputs()
57
+ for sKey in maps.getKeys(inputMap) {
58
+ inputFile := inputMap[sKey]
46
59
  key := json.decode(sKey)
47
60
  if len(key) != 1 {
48
61
  ll.panic("malformed key: %v", sKey)
@@ -121,6 +121,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
121
121
  columnsSpecPerSample := []
122
122
  columnsSpecPerSampleSc := undefined
123
123
  columnsSpecPerClonotype := []
124
+ columnsSpecPerClonotypeSc := undefined
124
125
 
125
126
  // array of array of arg groups
126
127
  exportArgs := []
@@ -211,6 +212,23 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
211
212
  mainAbundanceColumn = "uniqueMoleculeFraction"
212
213
  }
213
214
 
215
+ sampleCountColumn := {
216
+ column: "sampleCount",
217
+ id: "sample-count",
218
+ allowNA: false,
219
+ spec: {
220
+ name: "pl7.app/vdj/sampleCount",
221
+ valueType: "Int",
222
+ annotations: a(87110, true, {
223
+ "pl7.app/min": "1",
224
+ "pl7.app/isAbundance": "true",
225
+ "pl7.app/abundance/unit": "samples",
226
+ "pl7.app/abundance/normalized": "false",
227
+ "pl7.app/label": "Number of Samples"
228
+ })
229
+ }
230
+ }
231
+
214
232
  if isSingleCell {
215
233
  // copying reads and umi counts and fraction removing isPrimary and isAnchor
216
234
  columnsSpecPerSample = addSpec(columnsSpecPerSample, {
@@ -247,6 +265,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
247
265
  valueType: "Double",
248
266
  annotations: a(20000, false, {
249
267
  "pl7.app/min": "0",
268
+ "pl7.app/max": "1",
250
269
  "pl7.app/isAbundance": "true",
251
270
  "pl7.app/abundance/unit": "cells",
252
271
  "pl7.app/abundance/normalized": "true",
@@ -255,6 +274,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
255
274
  })
256
275
  }
257
276
  } ]
277
+ columnsSpecPerClonotypeSc = [ sampleCountColumn ]
278
+ } else {
279
+ columnsSpecPerClonotype += [ sampleCountColumn ]
258
280
  }
259
281
 
260
282
  orderP := 80000
@@ -478,6 +500,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
478
500
  // visibility: false
479
501
  // }
480
502
  ]
503
+ mainProductiveColumn := flagColumnVariants[0].columnPrefix + productiveFeature
504
+ mainProductiveArgs := [ flagColumnVariants[0].arg, productiveFeature ]
481
505
  for variant in flagColumnVariants {
482
506
  columnsSpecPerClonotype += [ {
483
507
  column: variant.columnPrefix + productiveFeature,
@@ -658,10 +682,13 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
658
682
  columnsSpecPerSample: columnsSpecPerSample,
659
683
  columnsSpecPerSampleSc: columnsSpecPerSampleSc,
660
684
  columnsSpecPerClonotype: columnsSpecPerClonotype,
685
+ columnsSpecPerClonotypeSc: columnsSpecPerClonotypeSc,
661
686
 
662
687
  columnsSpec: columnsSpec,
663
688
 
664
689
  mainAbundanceColumn: mainAbundanceColumn,
690
+ mainProductiveColumn: mainProductiveColumn,
691
+ mainProductiveArgs: mainProductiveArgs,
665
692
 
666
693
  exportArgs: exportArgs
667
694
  }
@@ -8,6 +8,7 @@ exec := import("@platforma-sdk/workflow-tengo:exec")
8
8
  assets := import("@platforma-sdk/workflow-tengo:assets")
9
9
  pcolumn := import("@platforma-sdk/workflow-tengo:pframes.pcolumn")
10
10
  times := import("times")
11
+ maps := import("@platforma-sdk/workflow-tengo:maps")
11
12
 
12
13
  json := import("json")
13
14
 
@@ -92,16 +93,19 @@ self.body(func(inputs) {
92
93
  arg(preset.name)
93
94
  }
94
95
 
96
+ inputMap := inputData.inputs()
95
97
  if inputDataMeta.keyLength == 0 {
96
98
  ll.assert(aggregationAxesNames == [], "unexpected aggregation axes names")
97
- inputFile := inputData.inputs()["[]"]
99
+ // Assuming only one key "[]" exists here, no need for sorted iteration
100
+ inputFile := inputMap["[]"]
98
101
  ll.assert(!is_undefined(inputFile), "unexpected agg group structure")
99
102
  inputFileName := "input." + fileExtension
100
103
  mixcrCmdBuilder.addFile(inputFileName, inputFile)
101
104
  mixcrCmdBuilder.arg(inputFileName)
102
105
  } else if inputDataMeta.keyLength == 1 {
103
106
  ll.assert(aggregationAxesNames == ["pl7.app/sequencing/readIndex"], "unexpected aggregation axes names")
104
- for sKey, inputFile in inputData.inputs() {
107
+ for sKey in maps.getKeys(inputMap) {
108
+ inputFile := inputMap[sKey]
105
109
  key := json.decode(sKey)
106
110
  if len(key) != 1 {
107
111
  ll.panic("malformed key: %v", sKey)
@@ -115,7 +119,8 @@ self.body(func(inputs) {
115
119
  mixcrCmdBuilder.arg("input_{{R}}." + fileExtension)
116
120
  } else if inputDataMeta.keyLength == 2 {
117
121
  ll.assert(aggregationAxesNames == ["pl7.app/sequencing/lane", "pl7.app/sequencing/readIndex"], "unexpected aggregation axes names")
118
- for sKey, inputFile in inputData.inputs() {
122
+ for sKey in maps.getKeys(inputMap) {
123
+ inputFile := inputMap[sKey]
119
124
  key := json.decode(sKey)
120
125
  if len(key) != 2 {
121
126
  ll.panic("malformed key: %v", sKey)
@@ -37,6 +37,7 @@ self.body(func(inputs) {
37
37
  arg("--dont-split-files").
38
38
  arg("--drop-default-fields").
39
39
  arg("--reset-export-clone-table-splitting").
40
+ arg("--export-productive-clones-only").
40
41
  arg("--chains").arg(chains)
41
42
 
42
43
  if library {
@@ -3,10 +3,11 @@ self := import("@platforma-sdk/workflow-tengo:tpl.light")
3
3
  pConstants := import("@platforma-sdk/workflow-tengo:pframes.constants")
4
4
  assets := import("@platforma-sdk/workflow-tengo:assets")
5
5
  exec := import("@platforma-sdk/workflow-tengo:exec")
6
+ maps := import("@platforma-sdk/workflow-tengo:maps")
6
7
 
7
8
  json := import("json")
8
9
 
9
- self.defineOutputs("abundanceTsv", "propertiesAPrimaryTsv", "propertiesASecondaryTsv", "propertiesBPrimaryTsv", "propertiesBSecondaryTsv")
10
+ self.defineOutputs("abundanceTsv", "clonotypeTsv", "propertiesAPrimaryTsv", "propertiesASecondaryTsv", "propertiesBPrimaryTsv", "propertiesBSecondaryTsv")
10
11
 
11
12
  scGroupBuilderSw := assets.importSoftware("@platforma-open/milaboratories.mixcr-clonotyping-2.single-cell-scripts:sc-group-builder")
12
13
  scPreprocessingSw := assets.importSoftware("@platforma-open/milaboratories.mixcr-clonotyping-2.single-cell-scripts:preprocessing")
@@ -23,13 +24,17 @@ self.body(func(inputs) {
23
24
 
24
25
  // Creating files map
25
26
  filesMap := {}
26
- for k, v in byCellTagA.inputs() {
27
+ inputMapA := byCellTagA.inputs()
28
+ for k in maps.getKeys(inputMapA) {
29
+ v := inputMapA[k]
27
30
  key := json.decode(k)
28
31
  fileName := "by_cell_a_" + key[0] + ".tsv"
29
32
  filesMap[fileName] = v
30
33
  }
31
34
 
32
- for k, v in byCellTagB.inputs() {
35
+ inputMapB := byCellTagB.inputs()
36
+ for k in maps.getKeys(inputMapB) {
37
+ v := inputMapB[k]
33
38
  key := json.decode(k)
34
39
  fileName := "by_cell_b_" + key[0] + ".tsv"
35
40
  filesMap[fileName] = v
@@ -37,11 +42,10 @@ self.body(func(inputs) {
37
42
 
38
43
  scPreprocessingCmd := exec.builder().
39
44
  printErrStreamToStdout().
40
- software(scPreprocessingSw).
41
- addFiles(filesMap)
45
+ software(scPreprocessingSw)
42
46
 
43
- for name, f in filesMap {
44
- scPreprocessingCmd = scPreprocessingCmd.arg(name)
47
+ for name in maps.getKeys(filesMap) {
48
+ scPreprocessingCmd.addFile(name, filesMap[name]).arg(name)
45
49
  }
46
50
 
47
51
  // Data preprocessing
@@ -60,6 +64,7 @@ self.body(func(inputs) {
60
64
  software(scGroupBuilderSw).
61
65
  addFile("chain_a_output.tsv", chainAoutput).
62
66
  addFile("chain_b_output.tsv", chainBoutput).
67
+ arg("--only_full_clonotypes").
63
68
  arg("--chainA").arg("chain_a_output.tsv").
64
69
  arg("--chainB").arg("chain_b_output.tsv").
65
70
  arg("--output_clonotype").arg("clonotype.tsv").
@@ -97,6 +102,8 @@ self.body(func(inputs) {
97
102
  return {
98
103
  // must have sampleId and scClonotypeKey columns
99
104
  abundanceTsv: abundanceTsv,
105
+ // used for aggregates (i.e. sampleCount)
106
+ clonotypeTsv: clonotypeTsv,
100
107
 
101
108
  // must have scClonotypeKey columns
102
109
  propertiesAPrimaryTsv: scOutputCmd.getFile("properties_a_primary.tsv"),
@@ -197,7 +197,8 @@ self.body(func(inputs) {
197
197
  columnsSpecPerSample := exportSpecs.columnsSpecPerSample
198
198
  columnsSpecPerSampleSc := exportSpecs.columnsSpecPerSampleSc
199
199
  columnsSpecPerClonotype := exportSpecs.columnsSpecPerClonotype
200
- columnsSpec := exportSpecs.columnsSpec
200
+ columnsSpecPerClonotypeSc := exportSpecs.columnsSpecPerClonotypeSc
201
+ // columnsSpec := exportSpecs.columnsSpec
201
202
 
202
203
  clonotypeKeyColumns := exportSpecs.clonotypeKeyColumns
203
204
  clonotypeKeyArgs := exportSpecs.clonotypeKeyArgs
@@ -459,6 +460,16 @@ self.body(func(inputs) {
459
460
  },
460
461
  name: "abundanceTable",
461
462
  path: ["abundanceTsv"]
463
+ }, {
464
+ type: "Xsv",
465
+ xsvType: "tsv",
466
+ settings: {
467
+ axes: axesByScClonotypeKeyWithReceptor,
468
+ columns: columnsSpecPerClonotypeSc,
469
+ storageFormat: "Binary"
470
+ },
471
+ name: "aggregates",
472
+ path: ["clonotypeTsv"]
462
473
  } ]
463
474
 
464
475
  for chainIdx in [0, 1] {
@@ -545,6 +556,7 @@ self.body(func(inputs) {
545
556
  )
546
557
 
547
558
  singleCellResult.addXsvOutputToBuilder(clonotypes, "abundanceTable", "clonotypeProperties/abundance/" + receptor + "/")
559
+ singleCellResult.addXsvOutputToBuilder(clonotypes, "aggregates", "clonotypeProperties/aggregates/" + receptor + "/")
548
560
 
549
561
  singleCellResult.addXsvOutputToBuilder(clonotypes, "propertiesAPrimary", "clonotypeProperties/" + receptor + "/aPrimary/")
550
562
  singleCellResult.addXsvOutputToBuilder(clonotypes, "propertiesASecondary", "clonotypeProperties/" + receptor + "/aSecondary/")