@platforma-open/milaboratories.top-antibodies.workflow 1.1.0 → 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/.turbo/turbo-build.log +8 -4
- package/CHANGELOG.md +19 -0
- package/dist/tengo/lib/pf-umap-conv.lib.tengo +43 -0
- package/dist/tengo/lib/sampled-cols-conv.lib.tengo +45 -0
- package/dist/tengo/lib/sampled-cols-umap-conv.lib.tengo +38 -0
- package/dist/tengo/tpl/main.plj.gz +0 -0
- package/package.json +7 -4
- package/src/main.tpl.tengo +300 -2
- package/src/pf-umap-conv.lib.tengo +43 -0
- package/src/sampled-cols-conv.lib.tengo +45 -0
- package/src/sampled-cols-umap-conv.lib.tengo +38 -0
- package/src/wf.test.ts +0 -13
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
WARN Issue while reading "/home/runner/work/top-antibodies/top-antibodies/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
|
|
2
2
|
|
|
3
|
-
> @platforma-open/milaboratories.top-antibodies.workflow@1.
|
|
3
|
+
> @platforma-open/milaboratories.top-antibodies.workflow@1.2.0 build /home/runner/work/top-antibodies/top-antibodies/workflow
|
|
4
4
|
> rm -rf dist && pl-tengo check && pl-tengo build
|
|
5
5
|
|
|
6
|
-
info: Skipping unknown file type: wf.test.ts
|
|
7
6
|
Processing "src/main.tpl.tengo"...
|
|
7
|
+
Processing "src/pf-umap-conv.lib.tengo"...
|
|
8
|
+
Processing "src/sampled-cols-conv.lib.tengo"...
|
|
9
|
+
Processing "src/sampled-cols-umap-conv.lib.tengo"...
|
|
8
10
|
No syntax errors found.
|
|
9
|
-
info: Skipping unknown file type: wf.test.ts
|
|
10
11
|
info: Compiling 'dist'...
|
|
12
|
+
info: - writing /home/runner/work/top-antibodies/top-antibodies/workflow/dist/tengo/lib/pf-umap-conv.lib.tengo
|
|
13
|
+
info: - writing /home/runner/work/top-antibodies/top-antibodies/workflow/dist/tengo/lib/sampled-cols-conv.lib.tengo
|
|
14
|
+
info: - writing /home/runner/work/top-antibodies/top-antibodies/workflow/dist/tengo/lib/sampled-cols-umap-conv.lib.tengo
|
|
11
15
|
info: - writing /home/runner/work/top-antibodies/top-antibodies/workflow/dist/tengo/tpl/main.plj.gz
|
|
12
|
-
info:
|
|
16
|
+
info: Template Pack build done.
|
|
13
17
|
info: Template Pack build done.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @platforma-open/milaboratories.top-antibodies.workflow
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5ee90ac: Add CDR3 spectratype
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [5ee90ac]
|
|
12
|
+
- @platforma-open/milaboratories.top-antibodies.spectratype@1.1.0
|
|
13
|
+
|
|
14
|
+
## 1.1.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- 339a780: Main backbone
|
|
19
|
+
- Updated dependencies [339a780]
|
|
20
|
+
- @platforma-open/milaboratories.top-antibodies.software@1.0.1
|
|
21
|
+
|
|
3
22
|
## 1.1.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
getColumns := func(datasetSpec) {
|
|
4
|
+
return {
|
|
5
|
+
"axes": [
|
|
6
|
+
{
|
|
7
|
+
"column": "clonotypeKey",
|
|
8
|
+
"spec": datasetSpec.axesSpec[1]
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"columns": [
|
|
12
|
+
{
|
|
13
|
+
"column": "UMAP1",
|
|
14
|
+
"id": "umap1",
|
|
15
|
+
"allowNA": false,
|
|
16
|
+
"spec": {
|
|
17
|
+
"name": "pl7.app/vdj/umap1",
|
|
18
|
+
"valueType": "Double",
|
|
19
|
+
"annotations": {
|
|
20
|
+
"pl7.app/label": "UMAP Dim1"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"column": "UMAP2",
|
|
26
|
+
"id": "umap2",
|
|
27
|
+
"allowNA": false,
|
|
28
|
+
"spec": {
|
|
29
|
+
"name": "pl7.app/vdj/umap2",
|
|
30
|
+
"valueType": "Double",
|
|
31
|
+
"annotations": {
|
|
32
|
+
"pl7.app/label": "UMAP Dim2"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}],
|
|
36
|
+
"storageFormat": "Binary",
|
|
37
|
+
"partitionKeyLength": 0
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export ll.toStrict({
|
|
42
|
+
getColumns: getColumns
|
|
43
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
getColumns := func(datasetSpec, linkerAxisSpec) {
|
|
4
|
+
axes := [
|
|
5
|
+
{
|
|
6
|
+
"column": "clonotypeKey",
|
|
7
|
+
"spec": datasetSpec.axesSpec[1]
|
|
8
|
+
}]
|
|
9
|
+
|
|
10
|
+
if len(linkerAxisSpec) > 0 {
|
|
11
|
+
for key, val in linkerAxisSpec {
|
|
12
|
+
axes = axes + [
|
|
13
|
+
{
|
|
14
|
+
"column": key,
|
|
15
|
+
"spec": val
|
|
16
|
+
}]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
"axes": axes,
|
|
22
|
+
"columns": [
|
|
23
|
+
{
|
|
24
|
+
"column": "top",
|
|
25
|
+
"id": "link",
|
|
26
|
+
"allowNA": false,
|
|
27
|
+
"spec": {
|
|
28
|
+
"name": "pl7.app/vdj/sampling-column",
|
|
29
|
+
"valueType": "Int",
|
|
30
|
+
"domain": {},
|
|
31
|
+
"annotations": {
|
|
32
|
+
"pl7.app/label": "Sampling column",
|
|
33
|
+
"pl7.app/table/visibility": "optional"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"storageFormat": "Binary",
|
|
39
|
+
"partitionKeyLength": 0
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export ll.toStrict({
|
|
44
|
+
getColumns: getColumns
|
|
45
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
getColumns := func(datasetSpec) {
|
|
6
|
+
axes := [
|
|
7
|
+
{
|
|
8
|
+
"column": "clonotypeKey",
|
|
9
|
+
"spec": datasetSpec.axesSpec[1]
|
|
10
|
+
}]
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
"axes": axes,
|
|
14
|
+
"columns": [
|
|
15
|
+
{
|
|
16
|
+
"column": "top",
|
|
17
|
+
"id": "link2", // temporal change
|
|
18
|
+
"allowNA": false,
|
|
19
|
+
"spec": {
|
|
20
|
+
"name": "pl7.app/vdj/sampling-column-umap",
|
|
21
|
+
"valueType": "Int",
|
|
22
|
+
"domain": {},
|
|
23
|
+
"annotations": {
|
|
24
|
+
"pl7.app/label": "Top clonotypes",
|
|
25
|
+
"pl7.app/table/visibility": "optional",
|
|
26
|
+
"pl7.app/isSubset": "true"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"storageFormat": "Binary",
|
|
32
|
+
"partitionKeyLength": 0
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export ll.toStrict({
|
|
37
|
+
getColumns: getColumns
|
|
38
|
+
})
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-open/milaboratories.top-antibodies.workflow",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Block Workflow",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@platforma-sdk/workflow-tengo": "^4.
|
|
7
|
+
"@platforma-sdk/workflow-tengo": "^4.3.2",
|
|
8
|
+
"@platforma-open/milaboratories.top-antibodies.sample-clonotypes": "1.0.1",
|
|
9
|
+
"@platforma-open/milaboratories.top-antibodies.spectratype": "1.1.0",
|
|
10
|
+
"@platforma-open/milaboratories.top-antibodies.umap": "1.0.1"
|
|
8
11
|
},
|
|
9
12
|
"devDependencies": {
|
|
10
|
-
"@platforma-sdk/tengo-builder": "^2.
|
|
11
|
-
"@platforma-sdk/test": "^1.
|
|
13
|
+
"@platforma-sdk/tengo-builder": "^2.1.3",
|
|
14
|
+
"@platforma-sdk/test": "^1.30.24",
|
|
12
15
|
"vitest": "^2.1.8"
|
|
13
16
|
},
|
|
14
17
|
"scripts": {
|
package/src/main.tpl.tengo
CHANGED
|
@@ -1,11 +1,309 @@
|
|
|
1
1
|
// light block with no workflow
|
|
2
2
|
wf := import("@platforma-sdk/workflow-tengo:workflow")
|
|
3
|
+
exec := import("@platforma-sdk/workflow-tengo:exec")
|
|
4
|
+
assets:= import("@platforma-sdk/workflow-tengo:assets")
|
|
5
|
+
xsv := import("@platforma-sdk/workflow-tengo:pframes.xsv")
|
|
6
|
+
pframes := import("@platforma-sdk/workflow-tengo:pframes")
|
|
7
|
+
sampledColsConv := import(":sampled-cols-conv")
|
|
8
|
+
sampledColsUmapConv := import(":sampled-cols-umap-conv")
|
|
9
|
+
slices := import("@platforma-sdk/workflow-tengo:slices")
|
|
10
|
+
umapConv := import(":pf-umap-conv")
|
|
11
|
+
|
|
12
|
+
wf.prepare(func(args){
|
|
13
|
+
// We need a table with cluster ID (optional) | clonotype id | selected ranking columns
|
|
14
|
+
|
|
15
|
+
bundleBuilder := wf.createPBundleBuilder()
|
|
16
|
+
bundleBuilder.ignoreMissingDomains() // to make query work for both bulk and single cell data
|
|
17
|
+
bundleBuilder.addAnchor("main", args.inputAnchor)
|
|
18
|
+
|
|
19
|
+
for col in args.rankingOrder {
|
|
20
|
+
bundleBuilder.addSingle(col)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Add linker column
|
|
24
|
+
bundleBuilder.addMulti({
|
|
25
|
+
axes: [{ anchor: "main", idx: 1 }], // this will do partial axes match (unlike in the model)
|
|
26
|
+
annotations: { "pl7.app/isLinkerColumn": "true" },
|
|
27
|
+
partialAxesMatch: true
|
|
28
|
+
}, "linkers")
|
|
29
|
+
|
|
30
|
+
// Add full aa sequence column
|
|
31
|
+
bundleBuilder.addMulti({
|
|
32
|
+
axes: [{ anchor: "main", idx: 1 }],
|
|
33
|
+
annotations: {
|
|
34
|
+
"pl7.app/vdj/isAssemblingFeature": "true",
|
|
35
|
+
"pl7.app/vdj/isMainSequence": "true"
|
|
36
|
+
},
|
|
37
|
+
domain: {
|
|
38
|
+
"pl7.app/alphabet": "aminoacid"
|
|
39
|
+
}
|
|
40
|
+
}, "aaSequence")
|
|
41
|
+
|
|
42
|
+
// Add CDR3 sequences
|
|
43
|
+
bundleBuilder.addMulti({
|
|
44
|
+
axes: [{ anchor: "main", idx: 1 }], // Clonotype axis
|
|
45
|
+
name: "pl7.app/vdj/sequence",
|
|
46
|
+
domain: {
|
|
47
|
+
"pl7.app/alphabet": "aminoacid",
|
|
48
|
+
"pl7.app/vdj/feature": "CDR3" // Specify CDR3 feature
|
|
49
|
+
}
|
|
50
|
+
}, "cdr3Sequences") // New collection name for CDR3 sequences
|
|
51
|
+
|
|
52
|
+
// Add V gene
|
|
53
|
+
bundleBuilder.addMulti({
|
|
54
|
+
axes: [{ anchor: "main", idx: 1 }], // Clonotype axis
|
|
55
|
+
name: "pl7.app/vdj/geneHit",
|
|
56
|
+
domain: {
|
|
57
|
+
"pl7.app/vdj/reference": "VGene"
|
|
58
|
+
}
|
|
59
|
+
}, "VGenes")
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
columns: bundleBuilder.build()
|
|
63
|
+
}
|
|
64
|
+
})
|
|
3
65
|
|
|
4
66
|
wf.body(func(args) {
|
|
5
67
|
|
|
68
|
+
// Input arguments
|
|
69
|
+
columns := args.columns
|
|
70
|
+
datasetSpec := columns.getSpec(args.inputAnchor)
|
|
71
|
+
|
|
72
|
+
topClonotypes := args.topClonotypes
|
|
73
|
+
|
|
74
|
+
// Needed conditional variables
|
|
75
|
+
isSingleCell := datasetSpec.axesSpec[1].name == "pl7.app/vdj/scClonotypeKey"
|
|
76
|
+
|
|
77
|
+
// output containers
|
|
78
|
+
outputs := {}
|
|
79
|
+
|
|
80
|
+
////////// Clonotype Filtering //////////
|
|
81
|
+
|
|
82
|
+
// Build clonotype table
|
|
83
|
+
cloneTable := columns.xsvTableBuilder()
|
|
84
|
+
cloneTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
|
|
85
|
+
|
|
86
|
+
for i, col in args.rankingOrder {
|
|
87
|
+
cloneTable.add(col, {header: "Col" + string(i)})
|
|
88
|
+
|
|
89
|
+
// If column does not have main anchor axis we have to include theirs
|
|
90
|
+
colsSpec := columns.getSpec(col)
|
|
91
|
+
axesNames := slices.map(colsSpec.axesSpec, func (a) { return a.name})
|
|
92
|
+
if !slices.hasElement(axesNames, datasetSpec.axesSpec[1].name) {
|
|
93
|
+
for na, ax in colsSpec.axesSpec {
|
|
94
|
+
if ax.name != datasetSpec.axesSpec[1].name {
|
|
95
|
+
cloneTable.setAxisHeader(ax.name, "cluster_" + string(i) + string(na))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Columns gotten by query require .key
|
|
102
|
+
linkerAxisSpec := {}
|
|
103
|
+
for i, col in columns.getColumns("linkers") {
|
|
104
|
+
if datasetSpec.axesSpec[1].name == col.spec.axesSpec[1].name {
|
|
105
|
+
cloneTable.add(col.key, {header: "linker." + string(i)})
|
|
106
|
+
cloneTable.setAxisHeader(col.spec.axesSpec[0].name, "cluster_" + string(i))
|
|
107
|
+
linkerAxisSpec["cluster_" + string(i)] = col.spec.axesSpec[0]
|
|
108
|
+
} else if datasetSpec.axesSpec[1].name == col.spec.axesSpec[0].name {
|
|
109
|
+
cloneTable.add(col.key, {header: "linker." + string(i)})
|
|
110
|
+
cloneTable.setAxisHeader(col.spec.axesSpec[1].name, "cluster_" + string(i))
|
|
111
|
+
linkerAxisSpec["cluster_" + string(i)] = col.spec.axesSpec[1]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
cloneTable = cloneTable.build("csv")
|
|
115
|
+
|
|
116
|
+
if topClonotypes != undefined {
|
|
117
|
+
// Run sampling script
|
|
118
|
+
sampleClones := exec.builder().
|
|
119
|
+
software(assets.importSoftware("@platforma-open/milaboratories.top-antibodies.sample-clonotypes:main")).
|
|
120
|
+
addFile("filteredClonotypes.csv", cloneTable).
|
|
121
|
+
arg("--csv").arg("filteredClonotypes.csv").
|
|
122
|
+
arg("--n").arg(string(topClonotypes)).
|
|
123
|
+
arg("--out").arg("sampledClonotypes.csv").
|
|
124
|
+
saveFile("sampledClonotypes_top.csv").
|
|
125
|
+
printErrStreamToStdout().
|
|
126
|
+
saveStdoutContent().
|
|
127
|
+
cache(24 * 60 * 60 * 1000).
|
|
128
|
+
run()
|
|
129
|
+
|
|
130
|
+
// Store outputs
|
|
131
|
+
sampledColsParams := sampledColsConv.getColumns(datasetSpec, linkerAxisSpec)
|
|
132
|
+
sampledColumnsPf := xsv.importFile(sampleClones.getFile("sampledClonotypes_top.csv"), "csv", sampledColsParams)
|
|
133
|
+
outputs["sampledRows"] = pframes.exportFrame(sampledColumnsPf)
|
|
134
|
+
|
|
135
|
+
// Prepare filter col subset for UMAP
|
|
136
|
+
// Avoid taking cluster axis using other params
|
|
137
|
+
sampledColsUmapParams := sampledColsUmapConv.getColumns(datasetSpec)
|
|
138
|
+
sampledColsUmapPf := xsv.importFile(sampleClones.getFile("sampledClonotypes_top.csv"), "csv", sampledColsUmapParams)
|
|
139
|
+
outputs["sampledRowsUmap"] = pframes.exportFrame(sampledColsUmapPf)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
////////// UMAP //////////
|
|
143
|
+
// Generate input TSV with Clonotype ID and aa sequence
|
|
144
|
+
umapTable := columns.xsvTableBuilder()
|
|
145
|
+
umapTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
|
|
146
|
+
for col in columns.getColumns("aaSequence") {
|
|
147
|
+
if isSingleCell {
|
|
148
|
+
chainLabel := col.spec.domain["pl7.app/vdj/scClonotypeChain"]
|
|
149
|
+
umapTable.add(col.key, {header: "aaSequence." + chainLabel})
|
|
150
|
+
} else {
|
|
151
|
+
chainLabel := col.spec.axesSpec[0].domain["pl7.app/vdj/chain"]
|
|
152
|
+
umapTable.add(col.key, {header: "aaSequence." + chainLabel})
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
umapTable = umapTable.build("tsv")
|
|
156
|
+
|
|
157
|
+
// UMAP script should go here
|
|
158
|
+
umapClones := exec.builder().
|
|
159
|
+
software(assets.importSoftware("@platforma-open/milaboratories.top-antibodies.umap:main")).
|
|
160
|
+
addFile("sequences.tsv", umapTable).
|
|
161
|
+
arg("-i").arg("sequences.tsv").
|
|
162
|
+
arg("-u").arg("umap.tsv").
|
|
163
|
+
saveFile("umap.tsv").
|
|
164
|
+
printErrStreamToStdout().
|
|
165
|
+
saveStdoutContent().
|
|
166
|
+
cache(24 * 60 * 60 * 1000).
|
|
167
|
+
run()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
umapPf := xsv.importFile(umapClones.getFile("umap.tsv"), "tsv", umapConv.getColumns(datasetSpec))
|
|
171
|
+
outputs["umap"] = pframes.exportFrame(umapPf)
|
|
172
|
+
|
|
173
|
+
////////// CDR3 Length Calculation //////////
|
|
174
|
+
|
|
175
|
+
cdr3SeqTable := columns.xsvTableBuilder()
|
|
176
|
+
cdr3SeqTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
|
|
177
|
+
|
|
178
|
+
// Must deal with multiple CDR3 sequences (two for each cell in single cell data)
|
|
179
|
+
// Chain will be added in the header as cdr3Sequence.chain and used in python script
|
|
180
|
+
// Notice chain is in spec.domain for single cell data and spec.axesSpec[0].domain for bulk data
|
|
181
|
+
|
|
182
|
+
// Helper function to add chain information to the headers dynamically
|
|
183
|
+
chainMapping := {
|
|
184
|
+
"IG": { "A": "Heavy", "B": "Light" },
|
|
185
|
+
"TCRAB": { "A": "TRA", "B": "TRB" },
|
|
186
|
+
"TCRGD": { "A": "TRG", "B": "TRD" }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
makeHeaderName := func(col, baseHeaderName, isSingleCell) {
|
|
190
|
+
if isSingleCell {
|
|
191
|
+
chain := col.spec.domain["pl7.app/vdj/scClonotypeChain"] // e.g., "A", "B"
|
|
192
|
+
receptor := col.spec.axesSpec[0].domain["pl7.app/vdj/receptor"] // e.g., "IG", "TCRAB", "TCRGD"
|
|
193
|
+
chainLabel := chainMapping[receptor][chain]
|
|
194
|
+
return baseHeaderName + "." + chainLabel
|
|
195
|
+
} else {
|
|
196
|
+
// For bulk, if chain info is available (e.g. IGH, IGK, IGL)
|
|
197
|
+
chainFromDomain := col.spec.axesSpec[0].domain["pl7.app/vdj/chain"] // e.g. "IGH", "IGK"
|
|
198
|
+
if chainFromDomain != undefined {
|
|
199
|
+
return baseHeaderName + "." + chainFromDomain
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return baseHeaderName // Default header for bulk
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Process CDR3 sequences
|
|
206
|
+
cdr3Sequences := columns.getColumns("cdr3Sequences")
|
|
207
|
+
|
|
208
|
+
for col in cdr3Sequences {
|
|
209
|
+
headerName := makeHeaderName(col, "cdr3Sequence", isSingleCell)
|
|
210
|
+
cdr3SeqTable.add(col.key, {header: headerName})
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Process V genes
|
|
214
|
+
vGenes := columns.getColumns("VGenes")
|
|
215
|
+
|
|
216
|
+
for col in vGenes {
|
|
217
|
+
headerName := makeHeaderName(col, "vGene", isSingleCell)
|
|
218
|
+
cdr3SeqTable.add(col.key, {header: headerName})
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
cdr3SeqTableBuilt := cdr3SeqTable.build("tsv")
|
|
222
|
+
|
|
223
|
+
cdr3VspectratypeCmd := exec.builder().
|
|
224
|
+
software(assets.importSoftware("@platforma-open/milaboratories.top-antibodies.spectratype:main")).
|
|
225
|
+
addFile("cdr3_sequences_input.tsv", cdr3SeqTableBuilt).
|
|
226
|
+
arg("--input_tsv").arg("cdr3_sequences_input.tsv").
|
|
227
|
+
arg("--output_tsv").arg("cdr3_lengths.tsv").
|
|
228
|
+
saveFile("cdr3_lengths.tsv").
|
|
229
|
+
printErrStreamToStdout().
|
|
230
|
+
saveStdoutContent().
|
|
231
|
+
cache(24 * 60 * 60 * 1000).
|
|
232
|
+
run()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
// For spectratype structure is:
|
|
236
|
+
// [chain][cdr3Length][vGene] -> count
|
|
237
|
+
|
|
238
|
+
// Get the spec for the vGene column
|
|
239
|
+
vGeneSpec := columns.getSpec(vGenes[0].key)
|
|
240
|
+
|
|
241
|
+
// Set up the axes for the output data
|
|
242
|
+
axes := [
|
|
243
|
+
{
|
|
244
|
+
column: "chain",
|
|
245
|
+
spec: {
|
|
246
|
+
name: "pl7.app/vdj/chain",
|
|
247
|
+
type: "String", // For axis it is type, not valueType
|
|
248
|
+
annotations: { "pl7.app/label": "CDR3 chain" }
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
column: "cdr3Length",
|
|
253
|
+
spec: {
|
|
254
|
+
name: "pl7.app/vdj/sequenceLength",
|
|
255
|
+
type: "Int",
|
|
256
|
+
domain: {
|
|
257
|
+
"pl7.app/vdj/feature": "CDR3",
|
|
258
|
+
"pl7.app/alphabet": "aminoacid"
|
|
259
|
+
},
|
|
260
|
+
annotations: { "pl7.app/label": "CDR3 aa Length" }
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
column: "vGene",
|
|
265
|
+
spec: {
|
|
266
|
+
name: "pl7.app/vdj/geneHit",
|
|
267
|
+
type: "String",
|
|
268
|
+
domain: vGeneSpec.domain,
|
|
269
|
+
annotations: {
|
|
270
|
+
"pl7.app/label": "Best V gene"
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
]
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
spectratypeColumns := [
|
|
279
|
+
{
|
|
280
|
+
column: "count",
|
|
281
|
+
spec: {
|
|
282
|
+
name: "pl7.app/vdj/vSpectratype",
|
|
283
|
+
valueType: "Int",
|
|
284
|
+
domain: {
|
|
285
|
+
"pl7.app/vdj/feature": "CDR3",
|
|
286
|
+
"pl7.app/alphabet": "aminoacid"
|
|
287
|
+
},
|
|
288
|
+
annotations: { "pl7.app/label": "CDR3 V Spectratype" }
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
spectratypeSpec := {
|
|
294
|
+
axes: axes,
|
|
295
|
+
columns: spectratypeColumns,
|
|
296
|
+
storageFormat: "Binary",
|
|
297
|
+
partitionKeyLength: 0
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
cdr3VspectratypePf := xsv.importFile(cdr3VspectratypeCmd.getFile("cdr3_lengths.tsv"), "tsv", spectratypeSpec)
|
|
301
|
+
|
|
302
|
+
outputs["cdr3VspectratypePf"] = pframes.exportFrame(cdr3VspectratypePf)
|
|
303
|
+
//ll.print("CDR3 lengths PFrame imported.")
|
|
304
|
+
|
|
6
305
|
return {
|
|
7
|
-
outputs:
|
|
306
|
+
outputs: outputs,
|
|
8
307
|
exports: {}
|
|
9
308
|
}
|
|
10
309
|
})
|
|
11
|
-
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
getColumns := func(datasetSpec) {
|
|
4
|
+
return {
|
|
5
|
+
"axes": [
|
|
6
|
+
{
|
|
7
|
+
"column": "clonotypeKey",
|
|
8
|
+
"spec": datasetSpec.axesSpec[1]
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"columns": [
|
|
12
|
+
{
|
|
13
|
+
"column": "UMAP1",
|
|
14
|
+
"id": "umap1",
|
|
15
|
+
"allowNA": false,
|
|
16
|
+
"spec": {
|
|
17
|
+
"name": "pl7.app/vdj/umap1",
|
|
18
|
+
"valueType": "Double",
|
|
19
|
+
"annotations": {
|
|
20
|
+
"pl7.app/label": "UMAP Dim1"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"column": "UMAP2",
|
|
26
|
+
"id": "umap2",
|
|
27
|
+
"allowNA": false,
|
|
28
|
+
"spec": {
|
|
29
|
+
"name": "pl7.app/vdj/umap2",
|
|
30
|
+
"valueType": "Double",
|
|
31
|
+
"annotations": {
|
|
32
|
+
"pl7.app/label": "UMAP Dim2"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}],
|
|
36
|
+
"storageFormat": "Binary",
|
|
37
|
+
"partitionKeyLength": 0
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export ll.toStrict({
|
|
42
|
+
getColumns: getColumns
|
|
43
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
getColumns := func(datasetSpec, linkerAxisSpec) {
|
|
4
|
+
axes := [
|
|
5
|
+
{
|
|
6
|
+
"column": "clonotypeKey",
|
|
7
|
+
"spec": datasetSpec.axesSpec[1]
|
|
8
|
+
}]
|
|
9
|
+
|
|
10
|
+
if len(linkerAxisSpec) > 0 {
|
|
11
|
+
for key, val in linkerAxisSpec {
|
|
12
|
+
axes = axes + [
|
|
13
|
+
{
|
|
14
|
+
"column": key,
|
|
15
|
+
"spec": val
|
|
16
|
+
}]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
"axes": axes,
|
|
22
|
+
"columns": [
|
|
23
|
+
{
|
|
24
|
+
"column": "top",
|
|
25
|
+
"id": "link",
|
|
26
|
+
"allowNA": false,
|
|
27
|
+
"spec": {
|
|
28
|
+
"name": "pl7.app/vdj/sampling-column",
|
|
29
|
+
"valueType": "Int",
|
|
30
|
+
"domain": {},
|
|
31
|
+
"annotations": {
|
|
32
|
+
"pl7.app/label": "Sampling column",
|
|
33
|
+
"pl7.app/table/visibility": "optional"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"storageFormat": "Binary",
|
|
39
|
+
"partitionKeyLength": 0
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export ll.toStrict({
|
|
44
|
+
getColumns: getColumns
|
|
45
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
ll := import("@platforma-sdk/workflow-tengo:ll")
|
|
2
|
+
|
|
3
|
+
// modified from sampled-cols-conv.lib.tengo
|
|
4
|
+
|
|
5
|
+
getColumns := func(datasetSpec) {
|
|
6
|
+
axes := [
|
|
7
|
+
{
|
|
8
|
+
"column": "clonotypeKey",
|
|
9
|
+
"spec": datasetSpec.axesSpec[1]
|
|
10
|
+
}]
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
"axes": axes,
|
|
14
|
+
"columns": [
|
|
15
|
+
{
|
|
16
|
+
"column": "top",
|
|
17
|
+
"id": "link2", // temporal change
|
|
18
|
+
"allowNA": false,
|
|
19
|
+
"spec": {
|
|
20
|
+
"name": "pl7.app/vdj/sampling-column-umap",
|
|
21
|
+
"valueType": "Int",
|
|
22
|
+
"domain": {},
|
|
23
|
+
"annotations": {
|
|
24
|
+
"pl7.app/label": "Top clonotypes",
|
|
25
|
+
"pl7.app/table/visibility": "optional",
|
|
26
|
+
"pl7.app/isSubset": "true"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"storageFormat": "Binary",
|
|
32
|
+
"partitionKeyLength": 0
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export ll.toStrict({
|
|
37
|
+
getColumns: getColumns
|
|
38
|
+
})
|
package/src/wf.test.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
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
|
-
);
|