@platforma-open/milaboratories.top-antibodies.workflow 1.1.1 → 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.
@@ -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.1.1 build /home/runner/work/top-antibodies/top-antibodies/workflow
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
6
  Processing "src/main.tpl.tengo"...
7
+ Processing "src/pf-umap-conv.lib.tengo"...
7
8
  Processing "src/sampled-cols-conv.lib.tengo"...
9
+ Processing "src/sampled-cols-umap-conv.lib.tengo"...
8
10
  No syntax errors found.
9
11
  info: Compiling 'dist'...
12
+ info: - writing /home/runner/work/top-antibodies/top-antibodies/workflow/dist/tengo/lib/pf-umap-conv.lib.tengo
10
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
16
  info: Template Pack build done.
13
17
  info: Template Pack build done.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
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
+
3
14
  ## 1.1.1
4
15
 
5
16
  ### Patch 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
+ })
@@ -9,11 +9,11 @@ getColumns := func(datasetSpec, linkerAxisSpec) {
9
9
 
10
10
  if len(linkerAxisSpec) > 0 {
11
11
  for key, val in linkerAxisSpec {
12
- axes.push([
13
- {
14
- "column": key,
15
- "spec": val
16
- }])
12
+ axes = axes + [
13
+ {
14
+ "column": key,
15
+ "spec": val
16
+ }]
17
17
  }
18
18
 
19
19
  }
@@ -25,12 +25,11 @@ getColumns := func(datasetSpec, linkerAxisSpec) {
25
25
  "id": "link",
26
26
  "allowNA": false,
27
27
  "spec": {
28
- "name": "pl7.app/vdj/link",
28
+ "name": "pl7.app/vdj/sampling-column",
29
29
  "valueType": "Int",
30
30
  "domain": {},
31
31
  "annotations": {
32
- "pl7.app/isLinkerColumn": "true",
33
- "pl7.app/label": "Linker column",
32
+ "pl7.app/label": "Sampling column",
34
33
  "pl7.app/table/visibility": "optional"
35
34
  }
36
35
  }
@@ -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,15 +1,17 @@
1
1
  {
2
2
  "name": "@platforma-open/milaboratories.top-antibodies.workflow",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "Block Workflow",
6
6
  "dependencies": {
7
7
  "@platforma-sdk/workflow-tengo": "^4.3.2",
8
- "@platforma-open/milaboratories.top-antibodies.software": "1.0.1"
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"
9
11
  },
10
12
  "devDependencies": {
11
13
  "@platforma-sdk/tengo-builder": "^2.1.3",
12
- "@platforma-sdk/test": "^1.30.19",
14
+ "@platforma-sdk/test": "^1.30.24",
13
15
  "vitest": "^2.1.8"
14
16
  },
15
17
  "scripts": {
@@ -5,7 +5,9 @@ assets:= import("@platforma-sdk/workflow-tengo:assets")
5
5
  xsv := import("@platforma-sdk/workflow-tengo:pframes.xsv")
6
6
  pframes := import("@platforma-sdk/workflow-tengo:pframes")
7
7
  sampledColsConv := import(":sampled-cols-conv")
8
-
8
+ sampledColsUmapConv := import(":sampled-cols-umap-conv")
9
+ slices := import("@platforma-sdk/workflow-tengo:slices")
10
+ umapConv := import(":pf-umap-conv")
9
11
 
10
12
  wf.prepare(func(args){
11
13
  // We need a table with cluster ID (optional) | clonotype id | selected ranking columns
@@ -18,12 +20,43 @@ wf.prepare(func(args){
18
20
  bundleBuilder.addSingle(col)
19
21
  }
20
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
21
31
  bundleBuilder.addMulti({
22
32
  axes: [{ anchor: "main", idx: 1 }],
23
- partialAxesMatch: true,
24
- annotations: { "pl7.app/isLinkerColumn": "true" }
33
+ annotations: {
34
+ "pl7.app/vdj/isAssemblingFeature": "true",
35
+ "pl7.app/vdj/isMainSequence": "true"
25
36
  },
26
- "linker")
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")
27
60
 
28
61
  return {
29
62
  columns: bundleBuilder.build()
@@ -32,57 +65,245 @@ wf.prepare(func(args){
32
65
 
33
66
  wf.body(func(args) {
34
67
 
68
+ // Input arguments
35
69
  columns := args.columns
36
70
  datasetSpec := columns.getSpec(args.inputAnchor)
71
+
37
72
  topClonotypes := args.topClonotypes
73
+
74
+ // Needed conditional variables
75
+ isSingleCell := datasetSpec.axesSpec[1].name == "pl7.app/vdj/scClonotypeKey"
38
76
 
77
+ // output containers
78
+ outputs := {}
39
79
 
40
- clonoTable := columns.xsvTableBuilder()
41
- clonoTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
80
+ ////////// Clonotype Filtering //////////
81
+
82
+ // Build clonotype table
83
+ cloneTable := columns.xsvTableBuilder()
84
+ cloneTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
42
85
 
43
86
  for i, col in args.rankingOrder {
44
- clonoTable.add(col, {header: "Col" + string(i)})
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
+ }
45
99
  }
46
100
 
47
101
  // Columns gotten by query require .key
48
102
  linkerAxisSpec := {}
49
- for i, col in columns.getColumns("linker") {
103
+ for i, col in columns.getColumns("linkers") {
50
104
  if datasetSpec.axesSpec[1].name == col.spec.axesSpec[1].name {
51
- clonoTable.add(col.key, {header: "linker." + string(i)})
52
- clonoTable.setAxisHeader(col.spec.axesSpec[0].name, "cluster_" + string(i))
105
+ cloneTable.add(col.key, {header: "linker." + string(i)})
106
+ cloneTable.setAxisHeader(col.spec.axesSpec[0].name, "cluster_" + string(i))
53
107
  linkerAxisSpec["cluster_" + string(i)] = col.spec.axesSpec[0]
54
108
  } else if datasetSpec.axesSpec[1].name == col.spec.axesSpec[0].name {
55
- clonoTable.add(col.key, {header: "linker." + string(i)})
56
- clonoTable.setAxisHeader(col.spec.axesSpec[1].name, "cluster_" + string(i))
109
+ cloneTable.add(col.key, {header: "linker." + string(i)})
110
+ cloneTable.setAxisHeader(col.spec.axesSpec[1].name, "cluster_" + string(i))
57
111
  linkerAxisSpec["cluster_" + string(i)] = col.spec.axesSpec[1]
58
112
  }
59
-
60
113
  }
114
+ cloneTable = cloneTable.build("csv")
61
115
 
62
- clonoTable = clonoTable.build("csv")
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)
63
134
 
64
- sampleClones := exec.builder().
65
- software(assets.importSoftware("@platforma-open/milaboratories.top-antibodies.software:sample-clonotypes")).
66
- addFile("filteredClonotypes.csv", clonoTable).
67
- arg("--csv").arg("filteredClonotypes.csv").
68
- arg("--n").arg(string(topClonotypes)).
69
- arg("--out").arg("sampledClonotypes.csv").
70
- saveFile("sampledClonotypes_top.csv").
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").
71
164
  printErrStreamToStdout().
72
165
  saveStdoutContent().
73
166
  cache(24 * 60 * 60 * 1000).
74
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 //////////
75
174
 
76
- sampledColsParams := sampledColsConv.getColumns(datasetSpec, linkerAxisSpec)
77
- sampledColumnsPf := xsv.importFile(sampleClones.getFile("sampledClonotypes_top.csv"), "csv", sampledColsParams)
175
+ cdr3SeqTable := columns.xsvTableBuilder()
176
+ cdr3SeqTable.setAxisHeader(datasetSpec.axesSpec[1].name, "clonotypeKey")
78
177
 
79
- // we need to output all filtered data axis
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
80
181
 
81
- return {
82
- outputs: {
83
- "sampledColumns": pframes.exportFrame(sampledColumnsPf)
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
+ }
84
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
+
305
+ return {
306
+ outputs: outputs,
85
307
  exports: {}
86
308
  }
87
309
  })
88
-
@@ -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
+ })
@@ -9,11 +9,11 @@ getColumns := func(datasetSpec, linkerAxisSpec) {
9
9
 
10
10
  if len(linkerAxisSpec) > 0 {
11
11
  for key, val in linkerAxisSpec {
12
- axes.push([
13
- {
14
- "column": key,
15
- "spec": val
16
- }])
12
+ axes = axes + [
13
+ {
14
+ "column": key,
15
+ "spec": val
16
+ }]
17
17
  }
18
18
 
19
19
  }
@@ -25,12 +25,11 @@ getColumns := func(datasetSpec, linkerAxisSpec) {
25
25
  "id": "link",
26
26
  "allowNA": false,
27
27
  "spec": {
28
- "name": "pl7.app/vdj/link",
28
+ "name": "pl7.app/vdj/sampling-column",
29
29
  "valueType": "Int",
30
30
  "domain": {},
31
31
  "annotations": {
32
- "pl7.app/isLinkerColumn": "true",
33
- "pl7.app/label": "Linker column",
32
+ "pl7.app/label": "Sampling column",
34
33
  "pl7.app/table/visibility": "optional"
35
34
  }
36
35
  }
@@ -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
+ })