@datagrok/peptides 0.8.5 → 0.8.9

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/src/model.ts CHANGED
@@ -1,103 +1,125 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
3
  import {describe} from './describe';
4
- import {Subject} from 'rxjs';
5
-
6
- /**
7
- * Model class for SAR viewers that retrieves and stores data.
8
- *
9
- * @class SARViewerModel
10
- */
11
- class SARViewerModel {
12
- private viewerGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
13
- private viewerVGrid: Subject<DG.Grid> = new Subject<DG.Grid>();
14
- private statsDf: Subject<DG.DataFrame> = new Subject<DG.DataFrame>();
15
- private groupMapping: Subject<{[key: string]: string}> = new Subject<{[key: string]: string}>();
16
- public viewerGrid$;
17
- public viewerVGrid$;
18
- public statsDf$;
19
- public groupMapping$;
4
+ import {Subject, Observable} from 'rxjs';
5
+ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
+ import {addViewerToHeader, StackedBarChart} from './viewers/stacked-barchart-viewer';
7
+
8
+ export class PeptidesModel {
9
+ // private _viewerGrid: DG.Grid;
10
+ // private viewerVGrid: DG.Grid;
11
+ // private _statsDf: DG.DataFrame;
12
+ // private groupMapping: StringDictionary;
20
13
  private dataFrame: DG.DataFrame | null;
21
14
  private activityColumn: string | null;
22
15
  private activityScaling: string | null;
23
16
  private sourceGrid: DG.Grid | null;
24
17
  private twoColorMode: boolean | null;
25
18
  private initialBitset: DG.BitSet | null;
26
- private isUpdating = false;
27
- grouping: boolean;
28
-
29
- /**
30
- * Creates an instance of SARViewerModel.
31
- *
32
- * @memberof SARViewerModel
33
- */
34
- constructor() {
35
- this.dataFrame = null;
19
+ private isUpdating: boolean = false;
20
+ private grouping: boolean = false;
21
+ private substFlag = false;
22
+ private statsDataFrameSubject = new Subject<DG.DataFrame>();
23
+ private sarGridSubject = new Subject<DG.Grid>();
24
+ private sarVGridSubject = new Subject<DG.Grid>();
25
+ private groupMappingSubject = new Subject<StringDictionary>();
26
+ private substFlagSubject = new Subject<boolean>();
27
+ private static _modelName = 'peptidesModel';
28
+
29
+ private constructor(dataFrame: DG.DataFrame) {
30
+ this.dataFrame = dataFrame;
36
31
  this.activityColumn = null;
37
32
  this.activityScaling = null;
38
33
  this.sourceGrid = null;
39
34
  this.twoColorMode = null;
40
35
  this.initialBitset = null;
41
- this.grouping = false;
42
- this.viewerGrid$ = this.viewerGrid.asObservable();
43
- this.viewerVGrid$ = this.viewerVGrid.asObservable();
44
- this.statsDf$ = this.statsDf.asObservable();
45
- this.groupMapping$ = this.groupMapping.asObservable();
36
+
37
+ // this._statsDf = DG.DataFrame.create();
38
+ // this._viewerGrid = DG.Grid.create(this.statsDf);
39
+ // this.viewerVGrid = DG.Grid.create(this.statsDf);
40
+ // this.groupMapping = {};
41
+
42
+ // this.statsDataFrameObservable = new Observable(subject => subject.next(this.statsDf));
43
+ // this.sarGridObservable = new Observable(subject => subject.next(this.viewerGrid));
44
+ // this.sarVGridObservable = new Observable(subject => subject.next(this.viewerVGrid));
45
+ // this.groupMappingObservable = new Observable(subject => subject.next(this.groupMapping));
46
+ }
47
+
48
+ // get statsDf() {
49
+ // return this._statsDf;
50
+ // }
51
+
52
+ // get viewerGrid() {
53
+ // return this._viewerGrid;
54
+ // }
55
+
56
+ get onStatsDataFrameChanged(): Observable<DG.DataFrame> {
57
+ return this.statsDataFrameSubject.asObservable();
58
+ }
59
+
60
+ get onSARGridChanged(): Observable<DG.Grid> {
61
+ return this.sarGridSubject.asObservable();
62
+ }
63
+
64
+ get onSARVGridChanged(): Observable<DG.Grid> {
65
+ return this.sarVGridSubject.asObservable();
66
+ }
67
+
68
+ get onGroupMappingChanged(): Observable<StringDictionary> {
69
+ return this.groupMappingSubject.asObservable();
70
+ }
71
+
72
+ get onSubstFlagChanged(): Observable<boolean> {
73
+ return this.substFlagSubject.asObservable();
46
74
  }
47
75
 
48
- /**
49
- * Updates data with using specified parameters.
50
- *
51
- * @param {DG.DataFrame} df Working table.
52
- * @param {string} activityCol Activity column name.
53
- * @param {string} activityScaling Activity scaling method.
54
- * @param {DG.Grid} sourceGrid Working table grid.
55
- * @param {boolean} twoColorMode Bidirectional analysis enabled.
56
- * @param {(DG.BitSet | null)} initialBitset Initial bitset.
57
- * @param {boolean} grouping Grouping enabled.
58
- * @memberof SARViewerModel
59
- */
60
76
  async updateData(
61
- df: DG.DataFrame,
62
- activityCol: string,
63
- activityScaling: string,
64
- sourceGrid: DG.Grid,
65
- twoColorMode: boolean,
66
- initialBitset: DG.BitSet | null,
67
- grouping: boolean,
68
- ) {
69
- this.dataFrame = df;
70
- this.activityColumn = activityCol;
71
- this.activityScaling = activityScaling;
72
- this.sourceGrid = sourceGrid;
73
- this.twoColorMode = twoColorMode;
74
- this.initialBitset = initialBitset;
75
- this.grouping = grouping;
77
+ df: DG.DataFrame | null, activityCol: string | null, activityScaling: string | null, sourceGrid: DG.Grid | null,
78
+ twoColorMode: boolean | null, initialBitset: DG.BitSet | null, grouping: boolean | null) {
79
+ this.dataFrame = df ?? this.dataFrame;
80
+ this.activityColumn = activityCol ?? this.activityColumn;
81
+ this.activityScaling = activityScaling ?? this.activityScaling;
82
+ this.sourceGrid = sourceGrid ?? this.sourceGrid;
83
+ this.twoColorMode = twoColorMode ?? this.twoColorMode;
84
+ this.initialBitset = initialBitset ?? this.initialBitset;
85
+ this.grouping = grouping ?? this.grouping;
76
86
  await this.updateDefault();
77
87
  }
78
88
 
79
- /**
80
- * Update data using current parameters.
81
- *
82
- * @memberof SARViewerModel
83
- */
84
89
  async updateDefault() {
85
- if (
86
- this.dataFrame && this.activityColumn && this.activityScaling &&
87
- this.sourceGrid && this.twoColorMode !== null && !this.isUpdating
88
- ) {
90
+ if (this.dataFrame && this.activityColumn && this.activityScaling && this.sourceGrid &&
91
+ this.twoColorMode !== null && !this.isUpdating) {
89
92
  this.isUpdating = true;
90
93
  const [viewerGrid, viewerVGrid, statsDf, groupMapping] = await describe(
91
- this.dataFrame, this.activityColumn, this.activityScaling,
92
- this.sourceGrid, this.twoColorMode, this.initialBitset, this.grouping,
93
- );
94
- this.viewerGrid.next(viewerGrid);
95
- this.viewerVGrid.next(viewerVGrid);
96
- this.statsDf.next(statsDf);
97
- this.groupMapping.next(groupMapping);
94
+ this.dataFrame, this.activityColumn, this.activityScaling, this.sourceGrid, this.twoColorMode,
95
+ this.initialBitset, this.grouping);
96
+ this.statsDataFrameSubject.next(statsDf);
97
+ this.groupMappingSubject.next(groupMapping);
98
+ this.sarGridSubject.next(viewerGrid);
99
+ this.sarVGridSubject.next(viewerVGrid);
100
+ this.substFlag = !this.substFlag;
101
+ this.substFlagSubject.next(this.substFlag);
102
+
103
+ this.sourceGrid.invalidate();
104
+
98
105
  this.isUpdating = false;
99
106
  }
107
+
108
+ await this.updateBarchart();
100
109
  }
101
- }
102
110
 
103
- export const model = new SARViewerModel();
111
+ async updateBarchart() {
112
+ const stackedBarchart = await this.dataFrame?.plot.fromType('StackedBarChartAA') as StackedBarChart;
113
+ if (stackedBarchart && this.sourceGrid)
114
+ addViewerToHeader(this.sourceGrid, stackedBarchart);
115
+ }
116
+
117
+ static get modelName() {
118
+ return PeptidesModel._modelName;
119
+ }
120
+
121
+ static getOrInit(dataFrame: DG.DataFrame): PeptidesModel {
122
+ dataFrame.temp[PeptidesModel.modelName] ??= new PeptidesModel(dataFrame);
123
+ return dataFrame.temp[PeptidesModel.modelName];
124
+ }
125
+ }
@@ -0,0 +1,184 @@
1
+ /** HELM associated sdf libraries with monomer processing*/
2
+ export class MonomerLibrary {
3
+ private monomerFields: string[] = [
4
+ 'molecule', 'MonomerType', 'MonomerNaturalAnalogCode', 'MonomerName', 'MonomerCode', 'MonomerCaps', 'BranchMonomer',
5
+ ];
6
+ private library: {
7
+ [name: string]: {
8
+ mol: string,
9
+ type: string,
10
+ analogueCode: string,
11
+ linkages: { [link: string]: { atomNumber: number, type: string } }
12
+ }
13
+ } = {};
14
+ private monomers: string[] = [];
15
+
16
+ constructor(sdf: string) {
17
+ const sdfReader = new SDFReader();
18
+ const data = sdfReader.getColls(sdf);
19
+ this.monomerFields.forEach((f) => {
20
+ if (!(f in data))
21
+ throw new Error(`Monomer library was not compiled: ${f} field is absent in provided file`);
22
+
23
+ if (data[f].length != data.molecule.length)
24
+ throw new Error(`Monomer library was not compiled: ${f} field is not presented for each monomer`);
25
+ });
26
+
27
+ for (let i = 0; i < data.molecule.length; i++) {
28
+ const linkData = this.getLinkData(data.molecule[i], data.MonomerCaps[i], data.MonomerName[i]);
29
+ const entry = {
30
+ mol: data.molecule[i],
31
+ type: 'Peptide',
32
+ code: data.MonomerCode[i],
33
+ analogueCode: data.MonomerNaturalAnalogCode[i],
34
+ linkages: linkData,
35
+ };
36
+
37
+ const name = data.MonomerCode[i] !== '.' ? data.MonomerCode[i] : data.MonomerName[i];
38
+ this.library[name] = entry;
39
+ this.monomers.push(name);
40
+ }
41
+ }
42
+
43
+ /** getting full monomer information from monomer library*/
44
+ public getMonomerEntry(name: string) {
45
+ if (!this.monomers.includes(name))
46
+ throw new Error(`Monomer library do not contain ${name} monomer`);
47
+
48
+
49
+ return this.library[name];
50
+ }
51
+
52
+ /** getting mol as string for monomer*/
53
+ public getMonomerMol(name: string) {
54
+ if (!this.monomers.includes(name))
55
+ throw new Error(`Monomer library do not contain ${name} monomer`);
56
+
57
+
58
+ const entry = this.library[name];
59
+ let monomerMol = entry.mol.replace(/M RGP .+\n/, '');
60
+
61
+ //order matters
62
+ const links = Object.keys(entry.linkages);
63
+ for (let i = 0; i < links.length; i++)
64
+ monomerMol = monomerMol.replace('R#', entry.linkages[links[i]].type + ' ');
65
+
66
+
67
+ return monomerMol;
68
+ }
69
+
70
+ /** getting the list of the minomers available in library*/
71
+ get monomerNames() {
72
+ return this.monomers;
73
+ }
74
+
75
+ private getLinkData(mol: string, caps: string, name: string) {
76
+ const rawData = mol.match(/M RGP .+/);
77
+ if (rawData === null)
78
+ throw new Error(`Monomer library was not compiled: ${name} entry has no RGP`);
79
+
80
+
81
+ const types: { [code: string]: string } = {};
82
+ caps.split('\n')?.forEach((e) => {
83
+ types[e.match(/\d+/)![0]] = e.match(/(?<=\])\w+/)![0];
84
+ });
85
+
86
+ const data = rawData![0].replace('M RGP ', '').split(/\s+/);
87
+ const res: { [link: string]: { atomNumber: number, type: string } } = {};
88
+ for (let i = 0; i < parseInt(data[0]); i++) {
89
+ const code = parseInt(data[2 * i + 2]);
90
+ let type = '';
91
+ switch (code) {
92
+ case 1:
93
+ type = 'N-terminal';
94
+ break;
95
+ case 2:
96
+ type = 'C-terminal';
97
+ break;
98
+ case 3:
99
+ type = 'branch';
100
+ break;
101
+ default:
102
+ break;
103
+ }
104
+ res[type] = {atomNumber: parseInt(data[2 * i + 1]), type: types[code]};
105
+ }
106
+
107
+ return res;
108
+ }
109
+ }
110
+
111
+ //TODO: merge with Chem version
112
+ class SDFReader {
113
+ dataColls: { [_: string]: any };
114
+
115
+ constructor() {
116
+ this.dataColls = {'molecule': []};
117
+ }
118
+
119
+ getColls(content: string) {
120
+ this.read(content);
121
+ return this.dataColls;
122
+ }
123
+
124
+ read(content: string) {
125
+ content = content.replaceAll('\r', ''); //equalize old and new sdf standards
126
+ let startIndex = content.indexOf('$$$$', 0);
127
+ this.parse(content, 0, startIndex, (name: string, val: any) => { // TODO: type
128
+ this.dataColls[name] = [];
129
+ this.dataColls[name].push(val);
130
+ });
131
+ startIndex += 5;
132
+ while (startIndex > -1 && startIndex < content.length)
133
+ startIndex = this.readNext(content, startIndex);
134
+ }
135
+
136
+ readNext(content: string, startIndex: number) {
137
+ const nextStartIndex = content.indexOf('$$$$', startIndex);
138
+ if (nextStartIndex === -1)
139
+ return -1;
140
+ else {
141
+ this.parse(content, startIndex, nextStartIndex,
142
+ (name: string, val: number) => this.dataColls[name].push(val));
143
+ }
144
+
145
+ if (nextStartIndex > -1)
146
+ return nextStartIndex + 5;
147
+
148
+
149
+ return nextStartIndex;
150
+ }
151
+
152
+ parse(content: string, start: number, end: number, handler: any) {
153
+ const molEnd = +content.indexOf('M END\n', start) + 7;
154
+ let localEnd = start;
155
+ this.dataColls['molecule'].push(content.substr(start, molEnd - start));
156
+
157
+ start = molEnd;
158
+ while (localEnd < end) {
159
+ start = content.indexOf('> <', localEnd);
160
+ if (start === -1)
161
+ return;
162
+
163
+
164
+ start += 3;
165
+ localEnd = content.indexOf('>\n', start);
166
+ if (localEnd === -1)
167
+ return;
168
+
169
+
170
+ const propertyName = content.substring(start, localEnd);
171
+ start = localEnd + 2;
172
+
173
+ localEnd = content.indexOf('\n', start);
174
+ if (localEnd === -1)
175
+ localEnd = end;
176
+ else if (content[localEnd + 1] != '\n')
177
+ localEnd = content.indexOf('\n', ++localEnd);
178
+ ;
179
+
180
+ handler(propertyName, content.substring(start, localEnd));
181
+ localEnd += 2;
182
+ }
183
+ }
184
+ }
@@ -4,15 +4,16 @@ import {runTests} from '@datagrok-libraries/utils/src/test';
4
4
 
5
5
  import './tests/peptide-space-test';
6
6
  import './tests/peptides-tests';
7
+ import './tests/msa-tests';
7
8
 
8
9
  export const _package = new DG.Package();
9
10
 
10
11
  //name: test
11
12
  //input: string category {optional: true}
12
- //input: string test {optional: true}
13
+ //input: string t {optional: true}
13
14
  //output: dataframe result
14
15
  //top-menu: Tools | Dev | JS API Tests
15
- export async function test(category: string, test: string): Promise<DG.DataFrame> {
16
- const data = await runTests({category, test});
16
+ export async function test(category: string, t: string): Promise<DG.DataFrame> {
17
+ const data = await runTests({category, test: t});
17
18
  return DG.DataFrame.fromObjects(data)!;
18
19
  }
package/src/package.ts CHANGED
@@ -5,6 +5,7 @@ import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {
7
7
  AlignedSequenceCellRenderer,
8
+ AlignedSequenceDifferenceCellRenderer,
8
9
  AminoAcidsCellRenderer,
9
10
  } from './utils/cell-renderer';
10
11
  import {Logo} from './viewers/logo-viewer';
@@ -16,13 +17,14 @@ import {manualAlignmentWidget} from './widgets/manual-alignment';
16
17
  import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
17
18
  import {peptideMoleculeWidget, getMolecule} from './widgets/peptide-molecule';
18
19
  import {SubstViewer} from './viewers/subst-viewer';
19
- import {runKalign} from './utils/multiple-sequence-alignment';
20
+ import {substTableWidget} from './widgets/subst-table';
21
+ import {msaWidget} from './widgets/multiple-sequence-alignment';
20
22
 
21
23
  export const _package = new DG.Package();
22
- let tableGrid: DG.Grid;
23
- let currentDf: DG.DataFrame;
24
- let alignedSequenceCol: DG.Column;
25
- let view: DG.TableView;
24
+ let currentGrid: DG.Grid;
25
+ let currentTable: DG.DataFrame;
26
+ let alignedSequenceColumn: DG.Column;
27
+ let currentView: DG.TableView;
26
28
 
27
29
  async function main(chosenFile: string) {
28
30
  const pi = DG.TaskBarProgressIndicator.create('Loading Peptides');
@@ -31,16 +33,16 @@ async function main(chosenFile: string) {
31
33
  peptides.name = 'Peptides';
32
34
  peptides.setTag('dataType', 'peptides');
33
35
  const view = grok.shell.addTableView(peptides);
34
- tableGrid = view.grid;
36
+ currentGrid = view.grid;
35
37
  view.name = 'PeptidesView';
36
38
  grok.shell.windows.showProperties = true;
37
39
 
38
40
  pi.close();
39
41
  }
40
42
 
41
- //name: Peptides App
43
+ //name: Peptides
42
44
  //tags: app
43
- export function Peptides() {
45
+ export async function Peptides() {
44
46
  const wikiLink = ui.link('wiki', 'https://github.com/datagrok-ai/public/blob/master/help/domains/bio/peptides.md');
45
47
  const textLink = ui.inlineText(['For more details, see our ', wikiLink, '.']);
46
48
 
@@ -73,8 +75,8 @@ export function Peptides() {
73
75
  appDescription,
74
76
  ui.info([textLink]),
75
77
  ui.divH([
76
- ui.button('Open peptide sequences demonstration set', () => main('aligned.csv'), ''),
77
- ui.button('Open complex case demo', () => main('aligned_2.csv'), ''),
78
+ ui.button('Simple demo', () => main('aligned.csv'), ''),
79
+ ui.button('Complex demo', () => main('aligned_2.csv'), ''),
78
80
  ]),
79
81
  ]);
80
82
  }
@@ -84,14 +86,12 @@ export function Peptides() {
84
86
  //input: column col {semType: alignedSequence}
85
87
  //output: widget result
86
88
  export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
87
- if (col.getTag('isAnalysisApplicable') === 'false') {
89
+ if (!(col.temp['isAnalysisApplicable'] ?? true))
88
90
  return new DG.Widget(ui.divText('Analysis is not applicable'));
89
- }
90
- view = (grok.shell.v as DG.TableView);
91
- tableGrid = view.grid;
92
- currentDf = col.dataFrame;
93
- alignedSequenceCol = col;
94
- return await analyzePeptidesWidget(col, view, tableGrid, currentDf);
91
+
92
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
93
+ getOrDefineWIP(currentView, currentGrid, currentTable, col);
94
+ return await analyzePeptidesWidget(col, currentView, currentGrid, currentTable);
95
95
  }
96
96
 
97
97
  //name: peptide-sar-viewer
@@ -136,6 +136,17 @@ export async function peptideMolecule(peptide: string): Promise<DG.Widget> {
136
136
  return await peptideMoleculeWidget(peptide);
137
137
  }
138
138
 
139
+ //name: Peptide Molecule
140
+ //tags: panel, widgets
141
+ //input: string aar {semType: aminoAcids}
142
+ //output: widget result
143
+ export async function peptideMolecule2(aar: string): Promise<DG.Widget> {
144
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
145
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
146
+ const peptide = alignedSequenceColumn.get(currentTable.currentRowIdx);
147
+ return await peptideMolecule(peptide);
148
+ }
149
+
139
150
  //name: StackedBarChartAA
140
151
  //tags: viewer
141
152
  //output: viewer result
@@ -171,7 +182,10 @@ export function logov() {
171
182
  //input: string monomer {semType: aminoAcids}
172
183
  //output: widget result
173
184
  export function manualAlignment(monomer: string) {
174
- return manualAlignmentWidget(alignedSequenceCol, currentDf);
185
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
186
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
187
+ //TODO: recalculate Molfile and Molecule panels on sequence update
188
+ return manualAlignmentWidget(alignedSequenceColumn, currentTable);
175
189
  }
176
190
 
177
191
  //name: Peptide Space
@@ -179,7 +193,9 @@ export function manualAlignment(monomer: string) {
179
193
  //input: column col {semType: alignedSequence}
180
194
  //output: widget result
181
195
  export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
182
- const widget = new PeptideSimilaritySpaceWidget(col, view ?? grok.shell.v);
196
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
197
+ getOrDefineWIP(currentView, currentGrid, currentTable, col);
198
+ const widget = new PeptideSimilaritySpaceWidget(col, currentView);
183
199
  return await widget.draw();
184
200
  }
185
201
 
@@ -192,13 +208,50 @@ export async function peptideMolfile(peptide: string): Promise<DG.Widget> {
192
208
  return await grok.functions.call('Chem:molfile', {'smiles': smiles});
193
209
  }
194
210
 
211
+ //name: Molfile
212
+ //tags: panel, widgets
213
+ //input: string aar { semType: aminoAcids }
214
+ //output: widget result
215
+ export async function peptideMolfile2(aar: string): Promise<DG.Widget> {
216
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
217
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
218
+ const peptide = alignedSequenceColumn.get(currentTable.currentRowIdx);
219
+ return await peptideMolfile(peptide);
220
+ }
221
+
195
222
  //name: Multiple sequence alignment
196
223
  //tags: panel
197
224
  //input: column col {semType: alignedSequence}
198
225
  //output: dataframe result
199
226
  export async function multipleSequenceAlignment(col: DG.Column): Promise<DG.DataFrame> {
200
- const msaCol = await runKalign(col, true);
201
- const table = col.dataFrame;
202
- table.columns.add(msaCol);
203
- return table;
227
+ return await msaWidget(col);
228
+ }
229
+
230
+ //name: Substitution
231
+ //tags: panel, widgets
232
+ //input: dataframe table {semType: Substitution}
233
+ //output: widget result
234
+ export async function peptideSubstitution(table: DG.DataFrame): Promise<DG.Widget> {
235
+ return substTableWidget(table);
236
+ }
237
+
238
+ //name: alignedSequenceDifferenceCellRenderer
239
+ //tags: cellRenderer, cellRenderer-alignedSequenceDifference
240
+ //meta-cell-renderer-sem-type: alignedSequenceDifference
241
+ //output: grid_cell_renderer result
242
+ export function alignedSequenceDifferenceCellRenderer() {
243
+ return new AlignedSequenceDifferenceCellRenderer();
244
+ }
245
+
246
+ function getOrDefineWIP(
247
+ view?: DG.TableView, grid?: DG.Grid, dataframe?: DG.DataFrame, column?: DG.Column | null,
248
+ ): [DG.TableView, DG.Grid, DG.DataFrame, DG.Column] {
249
+ view ??= (grok.shell.v as DG.TableView);
250
+ grid ??= view.grid;
251
+ dataframe ??= grok.shell.t;
252
+ column ??= (dataframe.columns as DG.ColumnList).bySemType('alignedSequence');
253
+ if (column === null)
254
+ throw new Error('Table does not contain aligned sequence columns');
255
+
256
+ return [view, grid, dataframe, column];
204
257
  }