@platforma-open/milaboratories.sequence-properties.model 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.
package/dist/types.d.ts CHANGED
@@ -1,11 +1,16 @@
1
1
  import { PlDataTableStateV2, PlRef } from "@platforma-sdk/model";
2
+ import { GraphMakerState } from "@milaboratories/graph-maker";
2
3
 
3
4
  //#region src/types.d.ts
4
- type BlockData = {
5
+ type BlockDataV1 = {
5
6
  inputAnchor?: PlRef;
6
7
  tableState: PlDataTableStateV2;
7
8
  defaultBlockLabel?: string;
8
9
  };
10
+ type BlockData = BlockDataV1 & {
11
+ graphStateScatter: GraphMakerState;
12
+ graphStateHistogram: GraphMakerState;
13
+ };
9
14
  type BlockArgs = {
10
15
  inputAnchor: PlRef;
11
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;KAEY,SAAA;EACV,WAAA,GAAc,KAAA;EACd,UAAA,EAAY,kBAAA;EAIZ,iBAAA;AAAA;AAAA,KAGU,SAAA;EACV,WAAA,EAAa,KAAA;AAAA;AAAA,KAGH,YAAA;AAAA,KAMA,gBAAA;AAAA,KAEA,YAAA;EACV,IAAA,GAAO,YAAA;EACP,QAAA,GAAW,gBAAA;EACX,YAAA;EACA,QAAA;AAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;KAKY,WAAA;EACV,WAAA,GAAc,KAAA;EACd,UAAA,EAAY,kBAAA;EAIZ,iBAAA;AAAA;AAAA,KAGU,SAAA,GAAY,WAAA;EACtB,iBAAA,EAAmB,eAAA;EACnB,mBAAA,EAAqB,eAAA;AAAA;AAAA,KAGX,SAAA;EACV,WAAA,EAAa,KAAA;AAAA;AAAA,KAGH,YAAA;AAAA,KAMA,gBAAA;AAAA,KAEA,YAAA;EACV,IAAA,GAAO,YAAA;EACP,QAAA,GAAW,gBAAA;EACX,YAAA;EACA,QAAA;AAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-open/milaboratories.sequence-properties.model",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Block model",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,13 +14,14 @@
14
14
  "./dist/*": "./dist/*"
15
15
  },
16
16
  "dependencies": {
17
+ "@milaboratories/graph-maker": "1.3.3",
17
18
  "@milaboratories/helpers": "^1.14.1",
18
19
  "@platforma-sdk/model": "1.69.0"
19
20
  },
20
21
  "devDependencies": {
21
22
  "@milaboratories/ts-builder": "1.3.2",
22
23
  "@milaboratories/ts-configs": "1.2.3",
23
- "@platforma-sdk/block-tools": "2.7.16"
24
+ "@platforma-sdk/block-tools": "2.7.19"
24
25
  },
25
26
  "peerDependencies": {
26
27
  "@types/node": "*",
package/src/dataModel.ts CHANGED
@@ -1,6 +1,31 @@
1
+ import type { GraphMakerState } from "@milaboratories/graph-maker";
1
2
  import { createPlDataTableStateV2, DataModelBuilder } from "@platforma-sdk/model";
2
- import type { BlockData } from "./types";
3
+ import type { BlockData, BlockDataV1 } from "./types";
3
4
 
4
- export const blockDataModel = new DataModelBuilder().from<BlockData>("Ver_2026_04_28").init(() => ({
5
- tableState: createPlDataTableStateV2(),
6
- }));
5
+ const DEFAULT_SCATTER_STATE: GraphMakerState = {
6
+ title: "",
7
+ template: "dots",
8
+ currentTab: null,
9
+ };
10
+
11
+ const DEFAULT_HISTOGRAM_STATE: GraphMakerState = {
12
+ title: "",
13
+ template: "bins",
14
+ currentTab: null,
15
+ layersSettings: {
16
+ bins: { fillColor: "#99e099" },
17
+ },
18
+ };
19
+
20
+ export const blockDataModel = new DataModelBuilder()
21
+ .from<BlockDataV1>("Ver_2026_04_28")
22
+ .migrate<BlockData>("Ver_2026_05_05", (v1) => ({
23
+ ...v1,
24
+ graphStateScatter: { ...DEFAULT_SCATTER_STATE },
25
+ graphStateHistogram: { ...DEFAULT_HISTOGRAM_STATE },
26
+ }))
27
+ .init(() => ({
28
+ tableState: createPlDataTableStateV2(),
29
+ graphStateScatter: { ...DEFAULT_SCATTER_STATE },
30
+ graphStateHistogram: { ...DEFAULT_HISTOGRAM_STATE },
31
+ }));
package/src/index.ts CHANGED
@@ -1,4 +1,9 @@
1
- import type { ColumnSource, InferOutputsType } from "@platforma-sdk/model";
1
+ import type {
2
+ ColumnSource,
3
+ InferOutputsType,
4
+ PColumnIdAndSpec,
5
+ PFrameHandle,
6
+ } from "@platforma-sdk/model";
2
7
  import {
3
8
  Annotation,
4
9
  ArrayColumnProvider,
@@ -55,6 +60,13 @@ export const platforma = BlockModelV3.create(blockDataModel)
55
60
  if (ctx.data.inputAnchor === undefined) return undefined;
56
61
  const ownCols = ctx.outputs?.resolve("propertiesPf")?.getPColumns();
57
62
  if (ownCols === undefined) return undefined;
63
+ // `coverageTier` is set in workflow/main.tpl.tengo and surfaced via the
64
+ // `info` JSON resource. Allowed values are defined in types.ts::WorkflowInfo.
65
+ // Gate on `info` so the table renders consistently with the chosen aa
66
+ // column rather than briefly without it while `info` is still resolving.
67
+ const info = ctx.outputs?.resolve("info")?.getDataAsJson<WorkflowInfo>();
68
+ if (info === undefined) return undefined;
69
+ const tier = info.coverageTier;
58
70
 
59
71
  // Build sources explicitly: upstream cols from the result pool minus
60
72
  // anything traced back to this block, plus this block's own cols from
@@ -78,12 +90,48 @@ export const platforma = BlockModelV3.create(blockDataModel)
78
90
  anchors: { main: ctx.data.inputAnchor },
79
91
  selector: { mode: "enrichment" },
80
92
  },
81
- // UX policy (not in spec): default-show only this block's columns;
82
- // demote upstream cols to optional to keep the table uncluttered.
83
- // This block's cols fall through unmatched and keep the visibility
84
- // stamped at workflow-time (`pl7.app/table/visibility`).
93
+ // Default-visible: this block's columns + a single source amino-acid
94
+ // sequence column matching the analysed coverage tier. Reviewer asked
95
+ // for one sequence next to the properties full-chain VDJRegion when
96
+ // available (it contains the CDR3); CDR3 alone when that is all the
97
+ // input has; peptide for peptide mode. Chain A (heavy / alpha / gamma)
98
+ // only — chain B stays available via the column picker. Other upstream
99
+ // cols → optional. This block's cols fall through unmatched and keep
100
+ // their workflow-time `pl7.app/table/visibility` annotation.
85
101
  displayOptions: {
86
102
  visibility: [
103
+ {
104
+ match: (spec) => {
105
+ if (spec.domain?.["pl7.app/vdj/scClonotypeChain/index"] === "secondary") {
106
+ return false;
107
+ }
108
+ if (spec.domain?.["pl7.app/alphabet"] !== "aminoacid") return false;
109
+
110
+ const isVdj = spec.name === "pl7.app/vdj/sequence";
111
+ const isUniversal = spec.name === "pl7.app/sequence";
112
+ if (!isVdj && !isUniversal) return false;
113
+
114
+ const feature = isVdj
115
+ ? spec.domain?.["pl7.app/vdj/feature"]
116
+ : spec.domain?.["pl7.app/feature"];
117
+
118
+ if (tier === "peptide") {
119
+ return isUniversal && feature === "peptide";
120
+ }
121
+
122
+ const chain = spec.domain?.["pl7.app/vdj/scClonotypeChain"];
123
+ if (chain !== undefined && chain !== "A") return false;
124
+
125
+ if (tier === "full_chain") {
126
+ return feature === "VDJRegion" || feature === "VDJRegionInFrame";
127
+ }
128
+ if (tier === "cdr3_only" || tier === "partial") {
129
+ return feature === "CDR3";
130
+ }
131
+ return false;
132
+ },
133
+ visibility: "default",
134
+ },
87
135
  {
88
136
  match: (spec) =>
89
137
  !spec.annotations?.[Annotation.Trace]?.includes(
@@ -95,9 +143,56 @@ export const platforma = BlockModelV3.create(blockDataModel)
95
143
  },
96
144
  });
97
145
  })
146
+ .outputWithStatus("propertiesPfHandle", (ctx): PFrameHandle | undefined => {
147
+ const allPCols = ctx.outputs?.resolve("propertiesPf")?.getPColumns();
148
+ if (allPCols === undefined) return undefined;
149
+ // Drop the AA fraction column from the pframe entirely. Two-axis
150
+ // (variantKey × aminoAcid), at 50k peptides ~1M cells — enough to trip
151
+ // graph-maker's cell-count guard on its own. The picker already excludes
152
+ // it via `isNumericScalar` (axesSpec.length === 1), so the data was
153
+ // pure overhead.
154
+ const pCols = allPCols.filter((c) => c.spec.name !== "pl7.app/aaFraction");
155
+ // Use `ctx.createPFrame` instead of `createPFrameForGraphs`. The latter
156
+ // walks the result pool and pulls in this block's `exports.properties`
157
+ // — a `trace.inject`-stamped re-emission of every column already in
158
+ // `propertiesPf`, published for Lead Selection — so axis dropdowns
159
+ // show e.g. "Net Charge (pH7) / IG" twice. Same workaround chosen by
160
+ // cdr3-spectratype, batch-correction, cell-type-annotation, and
161
+ // dimensionality-reduction.
162
+ //
163
+ // Pull single-axis metadata anchored to the input dataset's two axes
164
+ // (idx 0 = sample, idx 1 = entity key) so sample groups / patient IDs /
165
+ // peptide abundance and similar cols remain available for grouping and
166
+ // filtering. Drop self-trace to keep our own exports out.
167
+ const inputAnchor = ctx.data.inputAnchor;
168
+ const upstreamMeta =
169
+ inputAnchor !== undefined
170
+ ? (
171
+ ctx.resultPool.getAnchoredPColumns({ main: inputAnchor }, [
172
+ { axes: [{ anchor: "main", idx: 0 }] },
173
+ { axes: [{ anchor: "main", idx: 1 }] },
174
+ ]) ?? []
175
+ ).filter(
176
+ (c) =>
177
+ !c.spec.annotations?.[Annotation.Trace]?.includes(
178
+ "milaboratories.sequence-properties",
179
+ ),
180
+ )
181
+ : [];
182
+ return ctx.createPFrame([...pCols, ...upstreamMeta]);
183
+ })
184
+ .output("propertiesPfCols", (ctx): PColumnIdAndSpec[] | undefined => {
185
+ const pCols = ctx.outputs?.resolve("propertiesPf")?.getPColumns();
186
+ if (pCols === undefined) return undefined;
187
+ return pCols.map((c) => ({ columnId: c.id, spec: c.spec }) satisfies PColumnIdAndSpec);
188
+ })
98
189
  .title(() => "Sequence Properties")
99
190
  .subtitle((ctx) => ctx.data.defaultBlockLabel ?? "")
100
- .sections(() => [{ type: "link" as const, href: "/" as const, label: "Main" }])
191
+ .sections(() => [
192
+ { type: "link" as const, href: "/" as const, label: "Main" },
193
+ { type: "link" as const, href: "/scatter" as const, label: "Scatterplot" },
194
+ { type: "link" as const, href: "/histogram" as const, label: "Histogram" },
195
+ ])
101
196
  .done();
102
197
 
103
198
  export type BlockOutputs = InferOutputsType<typeof platforma>;
package/src/types.ts CHANGED
@@ -1,6 +1,9 @@
1
+ import type { GraphMakerState } from "@milaboratories/graph-maker";
1
2
  import type { PlDataTableStateV2, PlRef } from "@platforma-sdk/model";
2
3
 
3
- export type BlockData = {
4
+ // Pre-Visualizations shape. Retained as the v1 type so the data-model
5
+ // migration chain stays well-typed.
6
+ export type BlockDataV1 = {
4
7
  inputAnchor?: PlRef;
5
8
  tableState: PlDataTableStateV2;
6
9
  // UI-only state. Tracks the selected input dataset's label so the block
@@ -9,6 +12,11 @@ export type BlockData = {
9
12
  defaultBlockLabel?: string;
10
13
  };
11
14
 
15
+ export type BlockData = BlockDataV1 & {
16
+ graphStateScatter: GraphMakerState;
17
+ graphStateHistogram: GraphMakerState;
18
+ };
19
+
12
20
  export type BlockArgs = {
13
21
  inputAnchor: PlRef;
14
22
  };