Skip to content

Commit 96209b8

Browse files
Merge pull request #38 from platforma-open/julenmendieta/MILAB-6617_adaptToSingleCellVhh
Julenmendieta/MILAB-6617_adaptToSingleCellVhh
2 parents d6eb9d8 + 2d8dbb8 commit 96209b8

7 files changed

Lines changed: 651 additions & 473 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
"@platforma-open/milaboratories.vj-usage.model": patch
3+
"@platforma-open/milaboratories.vj-usage.ui": patch
4+
"@platforma-open/milaboratories.vj-usage": patch
5+
---
6+
7+
Only offer single-cell chains that actually have columns. The chain selector was
8+
built from the receptor type alone, so on heavy-chain-only (VHH) single-cell input
9+
it still offered "Light" — picking it failed the workflow with `expected exactly 1
10+
V gene column for chain, got 0`. A new `availableScChains` model output reports the
11+
chains present for the selected dataset; the selector now lists only those (and is
12+
hidden when a single chain leaves nothing to choose).

model/src/index.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { BlockModelV3, createPFrameForGraphs } from "@platforma-sdk/model";
33
import { blockDataModel } from "./dataModel";
44
import type { BlockArgs } from "./types";
55

6-
export { getDefaultBlockLabel } from "./label";
76
export { blockDataModel } from "./dataModel";
7+
export { getDefaultBlockLabel } from "./label";
88
export type { BlockArgs, BlockData } from "./types";
99

1010
export const platforma = BlockModelV3.create(blockDataModel)
@@ -45,6 +45,43 @@ export const platforma = BlockModelV3.create(blockDataModel)
4545
return ctx.resultPool.getPColumnSpecByRef(ctx.data.datasetRef);
4646
})
4747

48+
// Single-cell IG chain letters ("A" = heavy, "B" = light) that actually have columns
49+
// for the selected dataset. Returns undefined — meaning "don't filter" — for bulk
50+
// data, non-IG receptors, and while the pool is resolving.
51+
.output("availableScChains", (ctx) => {
52+
const ref = ctx.data.datasetRef;
53+
if (ref === undefined) return undefined;
54+
55+
const spec = ctx.resultPool.getPColumnSpecByRef(ref);
56+
// Only single-cell IG can be single-chain (heavy-only VHH): bulk has no chain axis,
57+
// and single-cell TCR is always paired — nothing to filter in those cases.
58+
if (spec?.axesSpec[1]?.name !== "pl7.app/vdj/scClonotypeKey") return undefined;
59+
if (spec.axesSpec[1]?.domain?.["pl7.app/vdj/receptor"] !== "IG") return undefined;
60+
61+
// Ask for the V-gene-hit column per chain
62+
const vGeneCols = ctx.resultPool.getAnchoredPColumns(
63+
{ main: ref },
64+
[
65+
{
66+
axes: [{ anchor: "main", idx: 1 }],
67+
name: "pl7.app/vdj/geneHit",
68+
domain: { "pl7.app/vdj/reference": "VGene" },
69+
},
70+
],
71+
{ ignoreMissingDomains: true },
72+
);
73+
if (vGeneCols === undefined) return undefined; // pool still resolving
74+
75+
const chains = new Set<string>();
76+
for (const col of vGeneCols) {
77+
const domain = col.spec.domain;
78+
if (domain?.["pl7.app/vdj/scClonotypeChain/index"] !== "primary") continue;
79+
const letter = domain?.["pl7.app/vdj/scClonotypeChain"];
80+
if (letter) chains.add(letter);
81+
}
82+
return [...chains].sort();
83+
})
84+
4885
.outputWithStatus("pf", (ctx) => {
4986
const pCols = ctx.outputs?.resolve("pf")?.getPColumns();
5087
if (pCols === undefined) {

0 commit comments

Comments
 (0)