@platforma-open/milaboratories.mixcr-clonotyping-2.workflow 2.17.0 → 2.18.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +9 -0
- package/dist/tengo/lib/calculate-export-specs.lib.tengo +154 -23
- package/dist/tengo/tpl/aggregate-by-clonotype-key.plj.gz +0 -0
- package/dist/tengo/tpl/calculate-preset-info.plj.gz +0 -0
- package/dist/tengo/tpl/list-presets.plj.gz +0 -0
- package/dist/tengo/tpl/main.plj.gz +0 -0
- package/dist/tengo/tpl/mixcr-analyze.plj.gz +0 -0
- package/dist/tengo/tpl/mixcr-export.plj.gz +0 -0
- package/dist/tengo/tpl/prerun.plj.gz +0 -0
- package/dist/tengo/tpl/process-single-cell.plj.gz +0 -0
- package/dist/tengo/tpl/process.plj.gz +0 -0
- package/dist/tengo/tpl/test.columns-calculate.plj.gz +0 -0
- package/dist/tengo/tpl/test.columns.test.plj.gz +0 -0
- package/package.json +5 -5
- package/src/aggregate-by-clonotype-key.tpl.tengo +14 -5
- package/src/calculate-export-specs.lib.tengo +156 -25
- package/src/process.tpl.tengo +4 -2
- package/src/test/columns.test.ts +2 -2
- package/.turbo/turbo-test.log +0 -21
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/work/mixcr-clonotyping/mixcr-clonotyping/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.
|
|
3
|
+
> @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.18.0 build /home/runner/work/mixcr-clonotyping/mixcr-clonotyping/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
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @platforma-open/milaboratories.mixcr-clonotyping.workflow
|
|
2
2
|
|
|
3
|
+
## 2.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2a9ce2a: - added two aggregated columns: Mean Fraction Of UMIs/Reads, Supprting UMIs/Reads
|
|
8
|
+
- support for RNA-Seq preset
|
|
9
|
+
- fallback for in-frame features for amino-acid sequence columns (for FR4 and VDJRegion)
|
|
10
|
+
- annotation strings for nucleotide and amino-acid sequences of assembling feature
|
|
11
|
+
|
|
3
12
|
## 2.17.0
|
|
4
13
|
|
|
5
14
|
### Minor Changes
|
|
@@ -7,10 +7,24 @@ json := import("json")
|
|
|
7
7
|
a := func(order, defaultVisibility, spec) {
|
|
8
8
|
return maps.merge(spec, {
|
|
9
9
|
"pl7.app/table/orderPriority": string(order),
|
|
10
|
-
"pl7.app/table/visibility": defaultVisibility ? "default" : "optional"
|
|
10
|
+
"pl7.app/table/visibility": is_undefined(defaultVisibility) ? "hidden" : defaultVisibility ? "default" : "optional"
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
inFrameFeatures := {
|
|
19
|
+
"FR4": "FR4InFrame",
|
|
20
|
+
"VDJRegion": "VDJRegionInFrame"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
annotationMappings := {
|
|
24
|
+
"CDRs": "{\"1\":\"CDR1\",\"2\":\"CDR2\",\"3\":\"CDR3\"}",
|
|
25
|
+
"Segments": "{\"1\":\"V\",\"2\":\"D\",\"3\":\"J\",\"4\":\"C\"}"
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
toCombinedDomainValue := func(spec) {
|
|
15
29
|
result := [spec.name]
|
|
16
30
|
|
|
@@ -42,7 +56,7 @@ assemblingFeatureInfo := func(assemblingFeature) {
|
|
|
42
56
|
if assemblingFeature == "CDR3" {
|
|
43
57
|
productiveFeature = "CDR3"
|
|
44
58
|
} else if assemblingFeature == "VDJRegion" {
|
|
45
|
-
productiveFeature = "
|
|
59
|
+
productiveFeature = "VDJRegionInFrame"
|
|
46
60
|
coreVFeature = "{FR1Begin:FR3End}"
|
|
47
61
|
coreJFeature = "FR4"
|
|
48
62
|
} else if len(splittedFeature1) == 2 {
|
|
@@ -116,8 +130,31 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
116
130
|
productiveFeature := assemblingFeatureInfo.productiveFeature
|
|
117
131
|
coreGeneFeatures := assemblingFeatureInfo.coreGeneFeatures
|
|
118
132
|
|
|
133
|
+
|
|
134
|
+
anchorFeature := undefined;
|
|
135
|
+
|
|
136
|
+
features := undefined
|
|
137
|
+
if is_undefined(assemblingFeature) {
|
|
138
|
+
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
assemblingFeature = "CDR3"
|
|
145
|
+
|
|
146
|
+
anchorFeature = "CDR3"
|
|
147
|
+
} else if assemblingFeature != "CDR3" {
|
|
148
|
+
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4", assemblingFeature]
|
|
149
|
+
anchorFeature = assemblingFeature
|
|
150
|
+
} else {
|
|
151
|
+
features = ["CDR3"]
|
|
152
|
+
anchorFeature = "CDR3"
|
|
153
|
+
}
|
|
154
|
+
|
|
119
155
|
clonotypeKeyColumns := undefined
|
|
120
156
|
clonotypeKeyArgs := undefined
|
|
157
|
+
|
|
121
158
|
if !is_undefined(assemblingFeature) {
|
|
122
159
|
clonotypeKeyColumns = ["nSeq" + assemblingFeature, "bestVGene", "bestJGene"]
|
|
123
160
|
clonotypeKeyArgs = [
|
|
@@ -129,7 +166,6 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
129
166
|
clonotypeKeyColumns += ["bestCGene"]
|
|
130
167
|
clonotypeKeyArgs += [ [ "-cGene" ] ]
|
|
131
168
|
}
|
|
132
|
-
|
|
133
169
|
}
|
|
134
170
|
|
|
135
171
|
columnsSpecPerSample := []
|
|
@@ -181,7 +217,42 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
181
217
|
[ "-readCount" ],
|
|
182
218
|
[ "-readFraction" ]
|
|
183
219
|
]
|
|
184
|
-
|
|
220
|
+
|
|
221
|
+
mainAbundanceColumnUnnormalized := "readCount"
|
|
222
|
+
mainAbundanceColumnNormalized := "readFraction"
|
|
223
|
+
|
|
224
|
+
mainAbundanceColumnAggregates := [{
|
|
225
|
+
column: mainAbundanceColumnUnnormalized + "Sum",
|
|
226
|
+
id: "read-count-total",
|
|
227
|
+
allowNA: false,
|
|
228
|
+
spec: {
|
|
229
|
+
name: "pl7.app/vdj/readCountTotal",
|
|
230
|
+
valueType: "Int",
|
|
231
|
+
annotations: a(87120, true, {
|
|
232
|
+
"pl7.app/min": "1",
|
|
233
|
+
"pl7.app/isAbundance": "true",
|
|
234
|
+
"pl7.app/abundance/unit": "reads",
|
|
235
|
+
"pl7.app/abundance/normalized": "false",
|
|
236
|
+
"pl7.app/label": "Supporting Reads"
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
}, {
|
|
240
|
+
column: mainAbundanceColumnNormalized + "Mean",
|
|
241
|
+
id: "read-fraction-mean",
|
|
242
|
+
allowNA: false,
|
|
243
|
+
spec: {
|
|
244
|
+
name: "pl7.app/vdj/readFractionMean",
|
|
245
|
+
valueType: "Double",
|
|
246
|
+
annotations: a(87130, true, {
|
|
247
|
+
"pl7.app/min": "0",
|
|
248
|
+
"pl7.app/max": "1",
|
|
249
|
+
"pl7.app/isAbundance": "true",
|
|
250
|
+
"pl7.app/abundance/unit": "reads",
|
|
251
|
+
"pl7.app/abundance/normalized": "true",
|
|
252
|
+
"pl7.app/label": "Mean Fraction of Reads"
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
}]
|
|
185
256
|
|
|
186
257
|
if hasUmi {
|
|
187
258
|
columnsSpecPerSample += [ {
|
|
@@ -223,7 +294,40 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
223
294
|
[ "-uniqueTagCount", "Molecule" ],
|
|
224
295
|
[ "-uniqueTagFraction", "Molecule" ]
|
|
225
296
|
]
|
|
226
|
-
|
|
297
|
+
mainAbundanceColumnNormalized = "uniqueMoleculeFraction"
|
|
298
|
+
mainAbundanceColumnUnnormalized = "uniqueMoleculeCount"
|
|
299
|
+
mainAbundanceColumnAggregates = [ {
|
|
300
|
+
column: mainAbundanceColumnUnnormalized + "Sum",
|
|
301
|
+
id: "umi-count-total",
|
|
302
|
+
allowNA: false,
|
|
303
|
+
spec: {
|
|
304
|
+
name: "pl7.app/vdj/uniqueMoleculeCountTotal",
|
|
305
|
+
valueType: "Long",
|
|
306
|
+
annotations: a(87120, true, {
|
|
307
|
+
"pl7.app/min": "1",
|
|
308
|
+
"pl7.app/isAbundance": "true",
|
|
309
|
+
"pl7.app/abundance/unit": "molecules",
|
|
310
|
+
"pl7.app/abundance/normalized": "false",
|
|
311
|
+
"pl7.app/label": "Supporting UMIs"
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
}, {
|
|
315
|
+
column: mainAbundanceColumnNormalized + "Mean",
|
|
316
|
+
id: "umi-fraction-mean",
|
|
317
|
+
allowNA: false,
|
|
318
|
+
spec: {
|
|
319
|
+
name: "pl7.app/vdj/uniqueMoleculeFractionMean",
|
|
320
|
+
valueType: "Double",
|
|
321
|
+
annotations: a(87130, true, {
|
|
322
|
+
"pl7.app/min": "0",
|
|
323
|
+
"pl7.app/max": "1",
|
|
324
|
+
"pl7.app/isAbundance": "true",
|
|
325
|
+
"pl7.app/abundance/unit": "molecules",
|
|
326
|
+
"pl7.app/abundance/normalized": "true",
|
|
327
|
+
"pl7.app/label": "Mean Fraction of UMIs"
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
} ]
|
|
227
331
|
}
|
|
228
332
|
|
|
229
333
|
sampleCountColumn := {
|
|
@@ -291,6 +395,7 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
291
395
|
columnsSpecPerClonotypeSc = [ sampleCountColumn ]
|
|
292
396
|
} else {
|
|
293
397
|
columnsSpecPerClonotype += [ sampleCountColumn ]
|
|
398
|
+
columnsSpecPerClonotype += mainAbundanceColumnAggregates
|
|
294
399
|
}
|
|
295
400
|
|
|
296
401
|
orderP := 80000
|
|
@@ -298,19 +403,8 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
298
403
|
|
|
299
404
|
|
|
300
405
|
|
|
301
|
-
anchorFeature := undefined;
|
|
302
406
|
|
|
303
|
-
|
|
304
|
-
if is_undefined(assemblingFeature) {
|
|
305
|
-
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
|
|
306
|
-
anchorFeature = "CDR3"
|
|
307
|
-
} else if assemblingFeature != "CDR3" {
|
|
308
|
-
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4", assemblingFeature]
|
|
309
|
-
anchorFeature = assemblingFeature
|
|
310
|
-
} else {
|
|
311
|
-
features = ["CDR3"]
|
|
312
|
-
anchorFeature = "CDR3"
|
|
313
|
-
}
|
|
407
|
+
annotationTypes := assemblingFeature == "CDR3" ? ["Segments"] : ["CDRs", "Segments"]
|
|
314
408
|
|
|
315
409
|
for isImputed in ( is_undefined(assemblingFeature) ? [false, true] : [false] ) {
|
|
316
410
|
imputedU := isImputed ? "Imputed" : ""
|
|
@@ -318,33 +412,68 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
318
412
|
for featureU in features {
|
|
319
413
|
featureL := text.to_lower(formatId(featureU))
|
|
320
414
|
for isAminoAcid in [true, false] {
|
|
415
|
+
featureInFrameU := isAminoAcid ? inFrameFeatures[featureU] : featureU
|
|
416
|
+
if is_undefined(featureInFrameU) {
|
|
417
|
+
featureInFrameU = featureU
|
|
418
|
+
}
|
|
419
|
+
featureInFrameL := text.to_lower(formatId(featureInFrameU))
|
|
420
|
+
|
|
321
421
|
alphabet := isAminoAcid ? "aminoacid" : "nucleotide"
|
|
322
422
|
alphabetShort := isAminoAcid ? "aa" : "nt"
|
|
323
423
|
alphabetShortMixcr := isAminoAcid ? "aa" : "n"
|
|
324
|
-
columnName := alphabetShortMixcr + "Seq" + imputedU +
|
|
424
|
+
columnName := alphabetShortMixcr + "Seq" + imputedU + featureInFrameU
|
|
325
425
|
visibility := featureU == "CDR3" && (!isSingleCell || isAminoAcid) // isSingleCell ? (featureU == "CDR3") && isAminoAcid : (featureU == "CDR3") || (featureU == assemblingFeature)
|
|
326
426
|
columnsSpecPerClonotype += [ {
|
|
327
427
|
column: columnName,
|
|
328
|
-
id: alphabetShortMixcr + "-seq-" +
|
|
428
|
+
id: alphabetShortMixcr + "-seq-" + featureInFrameL + (isImputed ? "-imputed" : ""),
|
|
329
429
|
naRegex: "region_not_covered",
|
|
330
430
|
spec: {
|
|
331
431
|
name: "pl7.app/vdj/sequence",
|
|
332
432
|
valueType: "String",
|
|
333
433
|
domain: {
|
|
334
|
-
"pl7.app/vdj/feature":
|
|
434
|
+
"pl7.app/vdj/feature": featureInFrameU,
|
|
335
435
|
"pl7.app/alphabet": alphabet
|
|
336
436
|
},
|
|
337
437
|
annotations: a(orderP, visibility, {
|
|
338
438
|
"pl7.app/vdj/isAssemblingFeature": featureU == anchorFeature ? "true" : "false",
|
|
439
|
+
"pl7.app/vdj/isMainSequence": featureU == anchorFeature ? "true" : "false",
|
|
339
440
|
"pl7.app/vdj/imputed": string(isImputed),
|
|
340
|
-
"pl7.app/label":
|
|
441
|
+
"pl7.app/label": featureInFrameU + " " + alphabetShort
|
|
341
442
|
})
|
|
342
443
|
}
|
|
343
444
|
} ]
|
|
344
|
-
exportArgs += [ [ "-" + alphabetShortMixcr + "Feature" + imputedU,
|
|
445
|
+
exportArgs += [ [ "-" + alphabetShortMixcr + "Feature" + imputedU, featureInFrameU ] ]
|
|
345
446
|
orderP -= 100
|
|
346
447
|
|
|
347
448
|
|
|
449
|
+
if !isImputed && featureU == assemblingFeature {
|
|
450
|
+
for annotationType in annotationTypes {
|
|
451
|
+
columnName := alphabetShortMixcr + "AnnotationOf" + annotationType + "For" + featureInFrameU
|
|
452
|
+
columnsSpecPerClonotype += [ {
|
|
453
|
+
column: columnName,
|
|
454
|
+
id: alphabetShortMixcr + "-annotation-" + annotationType + "-" + featureInFrameL,
|
|
455
|
+
naRegex: "region_not_covered",
|
|
456
|
+
spec: {
|
|
457
|
+
name: "pl7.app/vdj/sequence/annotation",
|
|
458
|
+
valueType: "String",
|
|
459
|
+
domain: {
|
|
460
|
+
"pl7.app/vdj/feature": featureInFrameU,
|
|
461
|
+
"pl7.app/alphabet": alphabet,
|
|
462
|
+
"pl7.app/sequence/annotation/type": annotationType
|
|
463
|
+
},
|
|
464
|
+
annotations: a(orderP, undefined, {
|
|
465
|
+
"pl7.app/label": annotationType + " annotation for " + featureInFrameU + " " + alphabetShort,
|
|
466
|
+
"pl7.app/sequence/annotation/mapping": annotationMappings[annotationType],
|
|
467
|
+
"pl7.app/sequence/isAnnotation": "true"
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
} ]
|
|
471
|
+
exportArgs += [ [ "-" + alphabetShortMixcr + "AnnotationString", annotationType, featureInFrameU ] ]
|
|
472
|
+
orderP -= 100
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
|
|
348
477
|
if featureU == "CDR3" {
|
|
349
478
|
columnsSpecPerClonotype += [ {
|
|
350
479
|
column: alphabetShortMixcr + "Length" + featureU,
|
|
@@ -701,7 +830,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
701
830
|
|
|
702
831
|
columnsSpec: columnsSpec,
|
|
703
832
|
|
|
704
|
-
|
|
833
|
+
mainAbundanceColumnNormalized: mainAbundanceColumnNormalized,
|
|
834
|
+
mainAbundanceColumnUnnormalized: mainAbundanceColumnUnnormalized,
|
|
835
|
+
|
|
705
836
|
mainProductiveColumn: mainProductiveColumn,
|
|
706
837
|
mainProductiveArgs: mainProductiveArgs,
|
|
707
838
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-open/milaboratories.mixcr-clonotyping-2.workflow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Tengo-based template",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@platforma-sdk/workflow-tengo": "^4.
|
|
6
|
+
"@platforma-sdk/workflow-tengo": "^4.3.2",
|
|
7
7
|
"@platforma-open/milaboratories.mixcr-clonotyping-2.single-cell-scripts": "1.1.3",
|
|
8
8
|
"@platforma-open/milaboratories.mixcr-clonotyping-2.hash-column": "1.1.1"
|
|
9
9
|
},
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@platforma-sdk/tengo-builder": "^2.1.
|
|
12
|
-
"@platforma-open/milaboratories.software-mixcr": "4.7.0-
|
|
11
|
+
"@platforma-sdk/tengo-builder": "^2.1.3",
|
|
12
|
+
"@platforma-open/milaboratories.software-mixcr": "4.7.0-169-develop",
|
|
13
13
|
"@platforma-open/milaboratories.software-ptransform": "^1.4.2",
|
|
14
|
-
"@platforma-sdk/test": "^1.
|
|
14
|
+
"@platforma-sdk/test": "^1.30.24",
|
|
15
15
|
"vitest": "~2.1.8",
|
|
16
16
|
"typescript": "~5.5.4"
|
|
17
17
|
},
|
|
@@ -19,12 +19,13 @@ self.body(func(inputs) {
|
|
|
19
19
|
ll.assert(inputDataMeta.keyLength == 1, "unexpected number of aggregation axes")
|
|
20
20
|
|
|
21
21
|
params := inputs.params
|
|
22
|
-
|
|
22
|
+
mainAbundanceColumnNormalized := params.mainAbundanceColumnNormalized
|
|
23
|
+
mainAbundanceColumnUnnormalized := params.mainAbundanceColumnUnnormalized
|
|
23
24
|
clonotypeColumns := params.clonotypeColumns
|
|
24
25
|
|
|
25
26
|
pickCols := []
|
|
26
27
|
for col in clonotypeColumns {
|
|
27
|
-
if col == "sampleCount" {
|
|
28
|
+
if col == "sampleCount" || col == mainAbundanceColumnNormalized + "Mean" || col == mainAbundanceColumnUnnormalized + "Sum" {
|
|
28
29
|
continue
|
|
29
30
|
}
|
|
30
31
|
pickCols = append(pickCols, [col, col])
|
|
@@ -37,13 +38,21 @@ self.body(func(inputs) {
|
|
|
37
38
|
groupBy: ["clonotypeKey"],
|
|
38
39
|
aggregations: [ {
|
|
39
40
|
type: "max_by",
|
|
40
|
-
rankingCol:
|
|
41
|
+
rankingCol: mainAbundanceColumnNormalized,
|
|
41
42
|
pickCols: pickCols
|
|
42
43
|
}, {
|
|
43
44
|
type: "count",
|
|
44
|
-
src:
|
|
45
|
+
src: mainAbundanceColumnNormalized,
|
|
45
46
|
dst: "sampleCount"
|
|
46
|
-
}
|
|
47
|
+
}, {
|
|
48
|
+
type: "sum",
|
|
49
|
+
src: mainAbundanceColumnUnnormalized,
|
|
50
|
+
dst: mainAbundanceColumnUnnormalized + "Sum"
|
|
51
|
+
}, {
|
|
52
|
+
type: "mean",
|
|
53
|
+
src: mainAbundanceColumnNormalized,
|
|
54
|
+
dst: mainAbundanceColumnNormalized + "Mean"
|
|
55
|
+
}]
|
|
47
56
|
} ]
|
|
48
57
|
}
|
|
49
58
|
|
|
@@ -7,10 +7,24 @@ json := import("json")
|
|
|
7
7
|
a := func(order, defaultVisibility, spec) {
|
|
8
8
|
return maps.merge(spec, {
|
|
9
9
|
"pl7.app/table/orderPriority": string(order),
|
|
10
|
-
"pl7.app/table/visibility": defaultVisibility ? "default" : "optional"
|
|
10
|
+
"pl7.app/table/visibility": is_undefined(defaultVisibility) ? "hidden" : defaultVisibility ? "default" : "optional"
|
|
11
11
|
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Mapping from original featuers to their in-frame variants when available.
|
|
16
|
+
* This is used to avoid showing non-informative features in the clonotype browser.
|
|
17
|
+
*/
|
|
18
|
+
inFrameFeatures := {
|
|
19
|
+
"FR4": "FR4InFrame",
|
|
20
|
+
"VDJRegion": "VDJRegionInFrame"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
annotationMappings := {
|
|
24
|
+
"CDRs": "{\"1\":\"CDR1\",\"2\":\"CDR2\",\"3\":\"CDR3\"}",
|
|
25
|
+
"Segments": "{\"1\":\"V\",\"2\":\"D\",\"3\":\"J\",\"4\":\"C\"}"
|
|
26
|
+
}
|
|
27
|
+
|
|
14
28
|
toCombinedDomainValue := func(spec) {
|
|
15
29
|
result := [spec.name]
|
|
16
30
|
// getKeys sort keys
|
|
@@ -42,7 +56,7 @@ assemblingFeatureInfo := func(assemblingFeature) {
|
|
|
42
56
|
if assemblingFeature == "CDR3" {
|
|
43
57
|
productiveFeature = "CDR3"
|
|
44
58
|
} else if assemblingFeature == "VDJRegion" {
|
|
45
|
-
productiveFeature = "
|
|
59
|
+
productiveFeature = "VDJRegionInFrame"
|
|
46
60
|
coreVFeature = "{FR1Begin:FR3End}"
|
|
47
61
|
coreJFeature = "FR4"
|
|
48
62
|
} else if len(splittedFeature1) == 2 {
|
|
@@ -116,8 +130,31 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
116
130
|
productiveFeature := assemblingFeatureInfo.productiveFeature
|
|
117
131
|
coreGeneFeatures := assemblingFeatureInfo.coreGeneFeatures
|
|
118
132
|
|
|
133
|
+
// column with nucleotide sequence of this feature will be marked as anchor
|
|
134
|
+
anchorFeature := undefined;
|
|
135
|
+
|
|
136
|
+
features := undefined
|
|
137
|
+
if is_undefined(assemblingFeature) {
|
|
138
|
+
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
|
|
139
|
+
|
|
140
|
+
// override assembling feature returned by the mixcr, we assume that if it is undefined,
|
|
141
|
+
// it means that the assembling feature is CDR3, and assemble contigs is executed with null
|
|
142
|
+
// subcloning region
|
|
143
|
+
// TODO return more detailed information from MiXCR
|
|
144
|
+
assemblingFeature = "CDR3"
|
|
145
|
+
|
|
146
|
+
anchorFeature = "CDR3"
|
|
147
|
+
} else if assemblingFeature != "CDR3" {
|
|
148
|
+
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4", assemblingFeature]
|
|
149
|
+
anchorFeature = assemblingFeature
|
|
150
|
+
} else {
|
|
151
|
+
features = ["CDR3"]
|
|
152
|
+
anchorFeature = "CDR3"
|
|
153
|
+
}
|
|
154
|
+
|
|
119
155
|
clonotypeKeyColumns := undefined
|
|
120
156
|
clonotypeKeyArgs := undefined
|
|
157
|
+
|
|
121
158
|
if !is_undefined(assemblingFeature) {
|
|
122
159
|
clonotypeKeyColumns = ["nSeq" + assemblingFeature, "bestVGene", "bestJGene"]
|
|
123
160
|
clonotypeKeyArgs = [
|
|
@@ -129,7 +166,6 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
129
166
|
clonotypeKeyColumns += ["bestCGene"]
|
|
130
167
|
clonotypeKeyArgs += [ [ "-cGene" ] ]
|
|
131
168
|
}
|
|
132
|
-
|
|
133
169
|
}
|
|
134
170
|
|
|
135
171
|
columnsSpecPerSample := []
|
|
@@ -181,7 +217,42 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
181
217
|
[ "-readCount" ],
|
|
182
218
|
[ "-readFraction" ]
|
|
183
219
|
]
|
|
184
|
-
|
|
220
|
+
|
|
221
|
+
mainAbundanceColumnUnnormalized := "readCount"
|
|
222
|
+
mainAbundanceColumnNormalized := "readFraction"
|
|
223
|
+
|
|
224
|
+
mainAbundanceColumnAggregates := [{
|
|
225
|
+
column: mainAbundanceColumnUnnormalized + "Sum",
|
|
226
|
+
id: "read-count-total",
|
|
227
|
+
allowNA: false,
|
|
228
|
+
spec: {
|
|
229
|
+
name: "pl7.app/vdj/readCountTotal",
|
|
230
|
+
valueType: "Int",
|
|
231
|
+
annotations: a(87120, true, {
|
|
232
|
+
"pl7.app/min": "1",
|
|
233
|
+
"pl7.app/isAbundance": "true",
|
|
234
|
+
"pl7.app/abundance/unit": "reads",
|
|
235
|
+
"pl7.app/abundance/normalized": "false",
|
|
236
|
+
"pl7.app/label": "Supporting Reads"
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
}, {
|
|
240
|
+
column: mainAbundanceColumnNormalized + "Mean",
|
|
241
|
+
id: "read-fraction-mean",
|
|
242
|
+
allowNA: false,
|
|
243
|
+
spec: {
|
|
244
|
+
name: "pl7.app/vdj/readFractionMean",
|
|
245
|
+
valueType: "Double",
|
|
246
|
+
annotations: a(87130, true, {
|
|
247
|
+
"pl7.app/min": "0",
|
|
248
|
+
"pl7.app/max": "1",
|
|
249
|
+
"pl7.app/isAbundance": "true",
|
|
250
|
+
"pl7.app/abundance/unit": "reads",
|
|
251
|
+
"pl7.app/abundance/normalized": "true",
|
|
252
|
+
"pl7.app/label": "Mean Fraction of Reads"
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
}]
|
|
185
256
|
|
|
186
257
|
if hasUmi {
|
|
187
258
|
columnsSpecPerSample += [ {
|
|
@@ -223,7 +294,40 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
223
294
|
[ "-uniqueTagCount", "Molecule" ],
|
|
224
295
|
[ "-uniqueTagFraction", "Molecule" ]
|
|
225
296
|
]
|
|
226
|
-
|
|
297
|
+
mainAbundanceColumnNormalized = "uniqueMoleculeFraction"
|
|
298
|
+
mainAbundanceColumnUnnormalized = "uniqueMoleculeCount"
|
|
299
|
+
mainAbundanceColumnAggregates = [ {
|
|
300
|
+
column: mainAbundanceColumnUnnormalized + "Sum",
|
|
301
|
+
id: "umi-count-total",
|
|
302
|
+
allowNA: false,
|
|
303
|
+
spec: {
|
|
304
|
+
name: "pl7.app/vdj/uniqueMoleculeCountTotal",
|
|
305
|
+
valueType: "Long",
|
|
306
|
+
annotations: a(87120, true, {
|
|
307
|
+
"pl7.app/min": "1",
|
|
308
|
+
"pl7.app/isAbundance": "true",
|
|
309
|
+
"pl7.app/abundance/unit": "molecules",
|
|
310
|
+
"pl7.app/abundance/normalized": "false",
|
|
311
|
+
"pl7.app/label": "Supporting UMIs"
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
}, {
|
|
315
|
+
column: mainAbundanceColumnNormalized + "Mean",
|
|
316
|
+
id: "umi-fraction-mean",
|
|
317
|
+
allowNA: false,
|
|
318
|
+
spec: {
|
|
319
|
+
name: "pl7.app/vdj/uniqueMoleculeFractionMean",
|
|
320
|
+
valueType: "Double",
|
|
321
|
+
annotations: a(87130, true, {
|
|
322
|
+
"pl7.app/min": "0",
|
|
323
|
+
"pl7.app/max": "1",
|
|
324
|
+
"pl7.app/isAbundance": "true",
|
|
325
|
+
"pl7.app/abundance/unit": "molecules",
|
|
326
|
+
"pl7.app/abundance/normalized": "true",
|
|
327
|
+
"pl7.app/label": "Mean Fraction of UMIs"
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
} ]
|
|
227
331
|
}
|
|
228
332
|
|
|
229
333
|
sampleCountColumn := {
|
|
@@ -291,26 +395,16 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
291
395
|
columnsSpecPerClonotypeSc = [ sampleCountColumn ]
|
|
292
396
|
} else {
|
|
293
397
|
columnsSpecPerClonotype += [ sampleCountColumn ]
|
|
398
|
+
columnsSpecPerClonotype += mainAbundanceColumnAggregates
|
|
294
399
|
}
|
|
295
400
|
|
|
296
401
|
orderP := 80000
|
|
297
402
|
|
|
298
403
|
// Sequences
|
|
299
404
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
features := undefined
|
|
304
|
-
if is_undefined(assemblingFeature) {
|
|
305
|
-
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4"]
|
|
306
|
-
anchorFeature = "CDR3"
|
|
307
|
-
} else if assemblingFeature != "CDR3" {
|
|
308
|
-
features = ["CDR1", "FR1", "FR2", "CDR2", "FR3", "CDR3", "FR4", assemblingFeature]
|
|
309
|
-
anchorFeature = assemblingFeature
|
|
310
|
-
} else {
|
|
311
|
-
features = ["CDR3"]
|
|
312
|
-
anchorFeature = "CDR3"
|
|
313
|
-
}
|
|
405
|
+
// nAnnotationOfCDRsForVDJRegionInFrame
|
|
406
|
+
// aaAnnotationOfSegmentsForVDJRegionInFrame
|
|
407
|
+
annotationTypes := assemblingFeature == "CDR3" ? ["Segments"] : ["CDRs", "Segments"]
|
|
314
408
|
|
|
315
409
|
for isImputed in ( is_undefined(assemblingFeature) ? [false, true] : [false] ) {
|
|
316
410
|
imputedU := isImputed ? "Imputed" : ""
|
|
@@ -318,32 +412,67 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
318
412
|
for featureU in features {
|
|
319
413
|
featureL := text.to_lower(formatId(featureU))
|
|
320
414
|
for isAminoAcid in [true, false] {
|
|
415
|
+
featureInFrameU := isAminoAcid ? inFrameFeatures[featureU] : featureU
|
|
416
|
+
if is_undefined(featureInFrameU) {
|
|
417
|
+
featureInFrameU = featureU
|
|
418
|
+
}
|
|
419
|
+
featureInFrameL := text.to_lower(formatId(featureInFrameU))
|
|
420
|
+
|
|
321
421
|
alphabet := isAminoAcid ? "aminoacid" : "nucleotide"
|
|
322
422
|
alphabetShort := isAminoAcid ? "aa" : "nt"
|
|
323
423
|
alphabetShortMixcr := isAminoAcid ? "aa" : "n"
|
|
324
|
-
columnName := alphabetShortMixcr + "Seq" + imputedU +
|
|
424
|
+
columnName := alphabetShortMixcr + "Seq" + imputedU + featureInFrameU
|
|
325
425
|
visibility := featureU == "CDR3" && (!isSingleCell || isAminoAcid) // isSingleCell ? (featureU == "CDR3") && isAminoAcid : (featureU == "CDR3") || (featureU == assemblingFeature)
|
|
326
426
|
columnsSpecPerClonotype += [ {
|
|
327
427
|
column: columnName,
|
|
328
|
-
id: alphabetShortMixcr + "-seq-" +
|
|
428
|
+
id: alphabetShortMixcr + "-seq-" + featureInFrameL + (isImputed ? "-imputed" : ""),
|
|
329
429
|
naRegex: "region_not_covered",
|
|
330
430
|
spec: {
|
|
331
431
|
name: "pl7.app/vdj/sequence",
|
|
332
432
|
valueType: "String",
|
|
333
433
|
domain: {
|
|
334
|
-
"pl7.app/vdj/feature":
|
|
434
|
+
"pl7.app/vdj/feature": featureInFrameU,
|
|
335
435
|
"pl7.app/alphabet": alphabet
|
|
336
436
|
},
|
|
337
437
|
annotations: a(orderP, visibility, {
|
|
338
438
|
"pl7.app/vdj/isAssemblingFeature": featureU == anchorFeature ? "true" : "false",
|
|
439
|
+
"pl7.app/vdj/isMainSequence": featureU == anchorFeature ? "true" : "false",
|
|
339
440
|
"pl7.app/vdj/imputed": string(isImputed),
|
|
340
|
-
"pl7.app/label":
|
|
441
|
+
"pl7.app/label": featureInFrameU + " " + alphabetShort
|
|
341
442
|
})
|
|
342
443
|
}
|
|
343
444
|
} ]
|
|
344
|
-
exportArgs += [ [ "-" + alphabetShortMixcr + "Feature" + imputedU,
|
|
445
|
+
exportArgs += [ [ "-" + alphabetShortMixcr + "Feature" + imputedU, featureInFrameU ] ]
|
|
345
446
|
orderP -= 100
|
|
346
447
|
|
|
448
|
+
// Adding sequence annotation columns for assembling feature
|
|
449
|
+
if !isImputed && featureU == assemblingFeature {
|
|
450
|
+
for annotationType in annotationTypes {
|
|
451
|
+
columnName := alphabetShortMixcr + "AnnotationOf" + annotationType + "For" + featureInFrameU
|
|
452
|
+
columnsSpecPerClonotype += [ {
|
|
453
|
+
column: columnName,
|
|
454
|
+
id: alphabetShortMixcr + "-annotation-" + annotationType + "-" + featureInFrameL,
|
|
455
|
+
naRegex: "region_not_covered",
|
|
456
|
+
spec: {
|
|
457
|
+
name: "pl7.app/vdj/sequence/annotation",
|
|
458
|
+
valueType: "String",
|
|
459
|
+
domain: {
|
|
460
|
+
"pl7.app/vdj/feature": featureInFrameU,
|
|
461
|
+
"pl7.app/alphabet": alphabet,
|
|
462
|
+
"pl7.app/sequence/annotation/type": annotationType
|
|
463
|
+
},
|
|
464
|
+
annotations: a(orderP, undefined, {
|
|
465
|
+
"pl7.app/label": annotationType + " annotation for " + featureInFrameU + " " + alphabetShort,
|
|
466
|
+
"pl7.app/sequence/annotation/mapping": annotationMappings[annotationType],
|
|
467
|
+
"pl7.app/sequence/isAnnotation": "true"
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
} ]
|
|
471
|
+
exportArgs += [ [ "-" + alphabetShortMixcr + "AnnotationString", annotationType, featureInFrameU ] ]
|
|
472
|
+
orderP -= 100
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
347
476
|
// For now calculate length only for CDR3 to keep the number of columns manageable
|
|
348
477
|
if featureU == "CDR3" {
|
|
349
478
|
columnsSpecPerClonotype += [ {
|
|
@@ -701,7 +830,9 @@ calculateExportSpecs := func(presetSpecForBack, blockId) {
|
|
|
701
830
|
|
|
702
831
|
columnsSpec: columnsSpec,
|
|
703
832
|
|
|
704
|
-
|
|
833
|
+
mainAbundanceColumnNormalized: mainAbundanceColumnNormalized,
|
|
834
|
+
mainAbundanceColumnUnnormalized: mainAbundanceColumnUnnormalized,
|
|
835
|
+
|
|
705
836
|
mainProductiveColumn: mainProductiveColumn,
|
|
706
837
|
mainProductiveArgs: mainProductiveArgs,
|
|
707
838
|
|
package/src/process.tpl.tengo
CHANGED
|
@@ -214,7 +214,8 @@ self.body(func(inputs) {
|
|
|
214
214
|
|
|
215
215
|
exportArgs := exportSpecs.exportArgs
|
|
216
216
|
|
|
217
|
-
|
|
217
|
+
mainAbundanceColumnNormalized := exportSpecs.mainAbundanceColumnNormalized
|
|
218
|
+
mainAbundanceColumnUnnormalized := exportSpecs.mainAbundanceColumnUnnormalized
|
|
218
219
|
|
|
219
220
|
if is_undefined(axesByClonotypeKey) {
|
|
220
221
|
ll.panic("Absent clonotype key not supported")
|
|
@@ -408,7 +409,8 @@ self.body(func(inputs) {
|
|
|
408
409
|
aggregate: ["pl7.app/sampleId"],
|
|
409
410
|
extra: {
|
|
410
411
|
params: {
|
|
411
|
-
|
|
412
|
+
mainAbundanceColumnNormalized: mainAbundanceColumnNormalized,
|
|
413
|
+
mainAbundanceColumnUnnormalized: mainAbundanceColumnUnnormalized,
|
|
412
414
|
clonotypeColumns: slices.map(columnsSpecPerClonotype, func(col) {
|
|
413
415
|
return col.column
|
|
414
416
|
})
|
package/src/test/columns.test.ts
CHANGED
|
@@ -59,7 +59,7 @@ const testCases: TestCase[] = [
|
|
|
59
59
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqCDR2')).toBeDefined();
|
|
60
60
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqFR3')).toBeDefined();
|
|
61
61
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqCDR3')).toBeDefined();
|
|
62
|
-
expect(config.columnsSpec.find((c: any) => c.column === '
|
|
62
|
+
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqFR4InFrame')).toBeDefined();
|
|
63
63
|
expect(config.columnsSpec.find((c: any) => c.column === 'topChains')).toBeDefined();
|
|
64
64
|
}
|
|
65
65
|
},
|
|
@@ -96,7 +96,7 @@ const testCases: TestCase[] = [
|
|
|
96
96
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqCDR2')).toBeDefined();
|
|
97
97
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqFR3')).toBeDefined();
|
|
98
98
|
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqCDR3')).toBeDefined();
|
|
99
|
-
expect(config.columnsSpec.find((c: any) => c.column === '
|
|
99
|
+
expect(config.columnsSpec.find((c: any) => c.column === 'aaSeqFR4InFrame')).toBeDefined();
|
|
100
100
|
expect(config.columnsSpec.find((c: any) => c.column === 'isotypePrimary')).toBeDefined();
|
|
101
101
|
}
|
|
102
102
|
},
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
WARN Issue while reading "/home/runner/work/mixcr-clonotyping/mixcr-clonotyping/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
|
-
|
|
3
|
-
> @platforma-open/milaboratories.mixcr-clonotyping-2.workflow@2.17.0 test /home/runner/work/mixcr-clonotyping/mixcr-clonotyping/workflow
|
|
4
|
-
> vitest
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
[1m[7m[36m RUN [39m[27m[22m [36mv2.1.8 [39m[90m/home/runner/work/mixcr-clonotyping/mixcr-clonotyping/workflow[39m
|
|
8
|
-
|
|
9
|
-
[32m✓[39m src/test/columns.test.ts [2m([22m[2m6 tests[22m[2m)[22m[33m 52852[2mms[22m[39m
|
|
10
|
-
[33m[2m✓[22m[39m checking preset for 'milab-human-dna-xcr-7genes-multiplex' [33m13107[2mms[22m[39m
|
|
11
|
-
[33m[2m✓[22m[39m checking preset for '10x-sc-xcr-vdj' [33m8442[2mms[22m[39m
|
|
12
|
-
[33m[2m✓[22m[39m checking preset for 'cellecta-human-rna-xcr-umi-drivermap-…' [33m7979[2mms[22m[39m
|
|
13
|
-
[33m[2m✓[22m[39m checking preset for 'takara-human-rna-bcr-umi-smartseq' [33m7987[2mms[22m[39m
|
|
14
|
-
[33m[2m✓[22m[39m checking preset for 'rna-seq' [33m7550[2mms[22m[39m
|
|
15
|
-
[33m[2m✓[22m[39m checking preset for 'generic-single-cell-gex' [33m7787[2mms[22m[39m
|
|
16
|
-
|
|
17
|
-
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
18
|
-
[2m Tests [22m [1m[32m6 passed[39m[22m[90m (6)[39m
|
|
19
|
-
[2m Start at [22m 15:43:08
|
|
20
|
-
[2m Duration [22m 53.65s[2m (transform 43ms, setup 0ms, collect 567ms, tests 52.85s, environment 0ms, prepare 58ms)[22m
|
|
21
|
-
|