@datagrok/peptides 1.0.2 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "author": {
5
5
  "name": "Volodymyr Dyma",
6
6
  "email": "vdyma@datagrok.ai"
@@ -12,13 +12,12 @@
12
12
  "directory": "packages/Peptides"
13
13
  },
14
14
  "dependencies": {
15
- "@biowasm/aioli": ">=2.4.0",
16
- "@datagrok-libraries/bio": "^2.8.6",
15
+ "@datagrok-libraries/bio": "^3.3.0",
17
16
  "@datagrok-libraries/ml": "^2.0.1",
18
17
  "@datagrok-libraries/statistics": "^0.1.6",
19
18
  "@datagrok-libraries/utils": "^0.4.1",
20
19
  "cash-dom": "latest",
21
- "datagrok-api": "latest",
20
+ "datagrok-api": "^1.6.0",
22
21
  "file-loader": "^6.2.0",
23
22
  "rxjs": "^6.5.5"
24
23
  },
@@ -38,12 +37,12 @@
38
37
  "jest": "^27.0.0",
39
38
  "@types/jest": "^27.0.0",
40
39
  "ts-jest": "^27.0.0",
41
- "puppeteer": "^13.7.0"
40
+ "puppeteer": "^13.7.0",
41
+ "@types/js-yaml": "^4.0.5",
42
+ "js-yaml": "^4.1.0",
43
+ "@types/node-fetch": "^2.6.2",
44
+ "node-fetch": "^2.6.7"
42
45
  },
43
- "sources": [
44
- "common/ngl_viewer/ngl.js",
45
- "helm/JSDraw/Pistoia.HELM.js"
46
- ],
47
46
  "scripts": {
48
47
  "link-api": "npm link datagrok-api",
49
48
  "link-utils": "npm link @datagrok-libraries/utils",
@@ -64,7 +63,7 @@
64
63
  "release-peptides-local": "grok publish local --release",
65
64
  "lint": "eslint \"./src/**/*.ts\"",
66
65
  "lint-fix": "eslint \"./src/**/*.ts\" --fix",
67
- "test": "set HOST=dev && jest",
66
+ "test": "jest",
68
67
  "test-dev": "set HOST=dev && jest",
69
68
  "test-local": "set HOST=localhost && jest"
70
69
  },
@@ -74,5 +73,5 @@
74
73
  "canView": [
75
74
  "All users"
76
75
  ],
77
- "category": "Cheminformatics"
76
+ "category": "Cheminformatics"
78
77
  }
@@ -5,7 +5,7 @@
5
5
  import * as utils from './test-node';
6
6
  import puppeteer from 'puppeteer';
7
7
 
8
- const P_START_TIMEOUT: number = 100000;
8
+ const P_START_TIMEOUT: number = 3600000;
9
9
  let browser: puppeteer.Browser;
10
10
  let page: puppeteer.Page;
11
11
 
@@ -46,15 +46,16 @@ it('TEST', async () => {
46
46
  const cMessage = df.columns.byName('result');
47
47
  const cCat = df.columns.byName('category');
48
48
  const cName = df.columns.byName('name');
49
+ const cTime = df.columns.byName('ms');
49
50
  let failed = false;
50
51
  let passReport = '';
51
52
  let failReport = '';
52
53
  for (let i = 0; i < df.rowCount; i++) {
53
54
  if (cStatus.get(i))
54
- passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
55
+ passReport += `Test result : Success : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
55
56
  else {
56
57
  failed = true;
57
- failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
58
+ failReport += `Test result : Failed : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
58
59
  }
59
60
  }
60
61
  resolve({failReport, passReport, failed});
@@ -65,4 +66,4 @@ it('TEST', async () => {
65
66
  console.log(r.passReport);
66
67
  // @ts-ignore
67
68
  expect(r.failed).checkOutput(false, r.failReport);
68
- }, 100000);
69
+ }, 3600000);
@@ -67,6 +67,7 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
67
67
  });
68
68
 
69
69
  const page = await browser.newPage();
70
+ await page.setDefaultNavigationTimeout(0);
70
71
  await page.goto(`${url}/oauth/`);
71
72
  await page.setCookie({name: 'auth', value: token});
72
73
  await page.evaluate((token: any) => {
@@ -74,8 +75,8 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
74
75
  }, token);
75
76
  await page.goto(url);
76
77
  try {
77
- await page.waitForSelector('.grok-preloader');
78
- await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 100000});
78
+ await page.waitForSelector('.grok-preloader', {timeout: 1800000});
79
+ await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 3600000});
79
80
  } catch (error) {
80
81
  throw error;
81
82
  }
package/src/model.ts CHANGED
@@ -2,30 +2,27 @@ import * as ui from 'datagrok-api/ui';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import {Subject, Observable} from 'rxjs';
5
+ import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
6
+
7
+ import * as rxjs from 'rxjs';
8
+
6
9
  import * as C from './utils/constants';
7
10
  import * as type from './utils/types';
8
- import {calculateBarsData, getTypedArrayConstructor, scaleActivity, splitAlignedPeptides} from './utils/misc';
9
- import {_package} from './package';
11
+ import {calculateBarsData, getTypedArrayConstructor, isGridCellInvalid, scaleActivity} from './utils/misc';
10
12
  import {SARViewer, SARViewerBase, SARViewerVertical} from './viewers/sar-viewer';
11
13
  import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
12
14
  import {renderBarchart, renderSARCell, setAARRenderer} from './utils/cell-renderer';
13
- import {substitutionsWidget} from './widgets/subst-table';
15
+ import {mutationCliffsWidget} from './widgets/mutation-cliffs';
14
16
  import {getDistributionAndStats, getDistributionWidget} from './widgets/distribution';
15
- import {getStats, Stats} from './utils/filtering-statistics';
16
- import * as rxjs from 'rxjs';
17
-
17
+ import {getStats, Stats} from './utils/statistics';
18
18
 
19
19
  export class PeptidesModel {
20
20
  static modelName = 'peptidesModel';
21
21
 
22
- _statsDataFrameSubject = new Subject<DG.DataFrame>();
23
- _sarGridSubject = new Subject<DG.Grid>();
24
- _sarVGridSubject = new Subject<DG.Grid>();
25
- _substitutionTableSubject = new Subject<type.SubstitutionsInfo>();
22
+ _sarGridSubject = new rxjs.Subject<DG.Grid>();
23
+ _sarVGridSubject = new rxjs.Subject<DG.Grid>();
26
24
 
27
25
  _isUpdating: boolean = false;
28
- _isSubstInitialized = false;
29
26
  isBitsetChangedInitialized = false;
30
27
  isCellChanging = false;
31
28
 
@@ -64,13 +61,9 @@ export class PeptidesModel {
64
61
  return dataFrame.temp[PeptidesModel.modelName] as PeptidesModel;
65
62
  }
66
63
 
67
- get onStatsDataFrameChanged(): Observable<DG.DataFrame> {return this._statsDataFrameSubject.asObservable();}
68
-
69
- get onSARGridChanged(): Observable<DG.Grid> {return this._sarGridSubject.asObservable();}
64
+ get onSARGridChanged(): rxjs.Observable<DG.Grid> {return this._sarGridSubject.asObservable();}
70
65
 
71
- get onSARVGridChanged(): Observable<DG.Grid> {return this._sarVGridSubject.asObservable();}
72
-
73
- get onSubstTableChanged(): Observable<type.SubstitutionsInfo> {return this._substitutionTableSubject.asObservable();}
66
+ get onSARVGridChanged(): rxjs.Observable<DG.Grid> {return this._sarVGridSubject.asObservable();}
74
67
 
75
68
  get currentSelection(): type.SelectionObject {
76
69
  this._currentSelection ??= JSON.parse(this.df.tags[C.TAGS.SELECTION] || '{}');
@@ -92,7 +85,7 @@ export class PeptidesModel {
92
85
  this._usedProperties = properties;
93
86
  }
94
87
 
95
- get splitByPos() {
88
+ get splitByPos(): boolean {
96
89
  const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[0];
97
90
  return splitByPosFlag == '1' ? true : false;
98
91
  }
@@ -101,7 +94,7 @@ export class PeptidesModel {
101
94
  this.df.tags['distributionSplit'] = `${flag ? 1 : 0}${splitByAARFlag}`;
102
95
  }
103
96
 
104
- get splitByAAR() {
97
+ get splitByAAR(): boolean {
105
98
  const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[1];
106
99
  return splitByPosFlag == '1' ? true : false;
107
100
  }
@@ -115,11 +108,11 @@ export class PeptidesModel {
115
108
  this.invalidateGrids();
116
109
  }
117
110
 
118
- createAccordion() {
111
+ createAccordion(): DG.Accordion {
119
112
  const acc = ui.accordion();
120
113
  acc.root.style.width = '100%';
121
114
  acc.addTitle(ui.h1(`${this.df.selection.trueCount} selected rows`));
122
- acc.addPane('Substitutions', () => substitutionsWidget(this.df, this).root, true);
115
+ acc.addPane('Substitutions', () => mutationCliffsWidget(this.df, this).root, true);
123
116
  acc.addPane('Distribtution', () => getDistributionWidget(this.df, this).root, true);
124
117
 
125
118
  return acc;
@@ -133,9 +126,11 @@ export class PeptidesModel {
133
126
  }
134
127
 
135
128
  isPropertyChanged(viewer: SARViewerBase): boolean {
136
- // const viewer = this.getViewer();
137
- const viewerProps = viewer.props.getProperties();
138
129
  let result = false;
130
+ if (typeof viewer == 'undefined')
131
+ return result;
132
+
133
+ const viewerProps = viewer.props.getProperties();
139
134
  const tempProps = this.usedProperties;
140
135
  for (const property of viewerProps) {
141
136
  const propName = property.name;
@@ -155,30 +150,25 @@ export class PeptidesModel {
155
150
  if ((this._sourceGrid && !this._isUpdating && proprtyChanged) || !this.isInitialized) {
156
151
  this.isInitialized = true;
157
152
  this._isUpdating = true;
158
- const [viewerGrid, viewerVGrid, statsDf] = this.initializeViewersComponents();
153
+ const [viewerGrid, viewerVGrid] = this.initializeViewersComponents();
159
154
  //FIXME: modify during the initializeViewersComponents stages
160
- this._statsDataFrameSubject.next(statsDf);
161
155
  this._sarGridSubject.next(viewerGrid);
162
156
  this._sarVGridSubject.next(viewerVGrid);
163
- if (viewer.showSubstitution) {
164
- this._substitutionTableSubject.next(this.substitutionsInfo);
165
- this._isSubstInitialized = true;
166
- }
167
157
 
168
158
  this.invalidateSelection();
169
-
170
159
  this._isUpdating = false;
171
160
  }
172
161
  }
173
162
 
174
- initializeViewersComponents(): [DG.Grid, DG.Grid, DG.DataFrame] {
163
+ initializeViewersComponents(): [DG.Grid, DG.Grid] {
175
164
  if (this._sourceGrid === null)
176
165
  throw new Error(`Source grid is not initialized`);
177
166
 
178
167
  //Split the aligned sequence into separate AARs
179
- const col: DG.Column = this.df.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
180
- const alphabet = col.tags[DG.TAGS.UNITS].split(':')[2];
181
- const splitSeqDf = splitAlignedPeptides(col);
168
+ const col: DG.Column<string> = this.df.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
169
+ // const alphabet = col.tags[DG.TAGS.UNITS].split(':')[2];
170
+ const alphabet = col.tags['alphabet'];
171
+ const splitSeqDf = splitAlignedSequences(col);
182
172
 
183
173
  this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
184
174
 
@@ -203,14 +193,14 @@ export class PeptidesModel {
203
193
  //unpivot a table and handle duplicates
204
194
  let matrixDf = splitSeqDf.groupBy(positionColumns).aggregate();
205
195
 
206
- matrixDf = matrixDf.unpivot([], positionColumns, C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
196
+ matrixDf = matrixDf.unpivot([], positionColumns, C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.MONOMER);
207
197
 
208
198
  //statistics for specific AAR at a specific position
209
199
  this.statsDf = this.calculateStatistics(matrixDf);
210
200
 
211
201
  // SAR matrix table
212
202
  //pivot a table to make it matrix-like
213
- matrixDf = this.statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE])
203
+ matrixDf = this.statsDf.groupBy([C.COLUMNS_NAMES.MONOMER])
214
204
  .pivot(C.COLUMNS_NAMES.POSITION)
215
205
  .add('first', C.COLUMNS_NAMES.MEAN_DIFFERENCE, '')
216
206
  .aggregate();
@@ -222,8 +212,7 @@ export class PeptidesModel {
222
212
  // SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
223
213
  const sequenceDf = this.createVerticalTable();
224
214
 
225
- if (viewer.showSubstitution || !this._isSubstInitialized)
226
- this.calcSubstitutions();
215
+ this.calcSubstitutions();
227
216
 
228
217
  const [sarGrid, sarVGrid] = this.createGrids(matrixDf, positionColumns, sequenceDf, alphabet);
229
218
 
@@ -246,7 +235,7 @@ export class PeptidesModel {
246
235
  this.postProcessGrids(sarGrid, sarVGrid);
247
236
 
248
237
  //TODO: return class instead
249
- return [sarGrid, sarVGrid, this.statsDf];
238
+ return [sarGrid, sarVGrid];
250
239
  }
251
240
 
252
241
  calcSubstitutions(): void {
@@ -383,7 +372,7 @@ export class PeptidesModel {
383
372
  }
384
373
 
385
374
  calculateStatistics(matrixDf: DG.DataFrame): DG.DataFrame {
386
- matrixDf = matrixDf.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).aggregate();
375
+ matrixDf = matrixDf.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.MONOMER]).aggregate();
387
376
 
388
377
  //calculate p-values based on t-test
389
378
  const matrixCols = matrixDf.columns;
@@ -391,7 +380,7 @@ export class PeptidesModel {
391
380
  const pValCol = matrixCols.addNewFloat(C.COLUMNS_NAMES.P_VALUE);
392
381
  const countCol = matrixCols.addNewInt(C.COLUMNS_NAMES.COUNT);
393
382
  const ratioCol = matrixCols.addNewFloat(C.COLUMNS_NAMES.RATIO);
394
- const aarCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
383
+ const aarCol = matrixDf.getCol(C.COLUMNS_NAMES.MONOMER);
395
384
  const posCol = matrixDf.getCol(C.COLUMNS_NAMES.POSITION);
396
385
  const activityCol: number[] = this.df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED).toList();
397
386
  const sourceDfLen = activityCol.length;
@@ -424,22 +413,22 @@ export class PeptidesModel {
424
413
  absMDCol.init((i) => Math.abs(mdCol.get(i)));
425
414
  }
426
415
 
427
- const aarWeightsDf = this.statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).sum(sortArgument, 'weight')
416
+ const aarWeightsDf = this.statsDf.groupBy([C.COLUMNS_NAMES.MONOMER]).sum(sortArgument, 'weight')
428
417
  .aggregate();
429
- const aarList = aarWeightsDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).toList();
418
+ const aarList = aarWeightsDf.getCol(C.COLUMNS_NAMES.MONOMER).toList();
430
419
  const getWeight = (aar: string): number => aarWeightsDf
431
420
  .groupBy(['weight'])
432
- .where(`${C.COLUMNS_NAMES.AMINO_ACID_RESIDUE} = ${aar}`)
421
+ .where(`${C.COLUMNS_NAMES.MONOMER} = ${aar}`)
433
422
  .aggregate()
434
423
  .get('weight', 0) as number;
435
424
  aarList.sort((first, second) => getWeight(second) - getWeight(first));
436
425
 
437
- matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).setCategoryOrder(aarList);
426
+ matrixDf.getCol(C.COLUMNS_NAMES.MONOMER).setCategoryOrder(aarList);
438
427
  }
439
428
 
440
429
  createVerticalTable(): DG.DataFrame {
441
430
  // TODO: aquire ALL of the positions
442
- const columns = [C.COLUMNS_NAMES.MEAN_DIFFERENCE, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, C.COLUMNS_NAMES.POSITION,
431
+ const columns = [C.COLUMNS_NAMES.MEAN_DIFFERENCE, C.COLUMNS_NAMES.MONOMER, C.COLUMNS_NAMES.POSITION,
443
432
  'Count', 'Ratio', C.COLUMNS_NAMES.P_VALUE];
444
433
  let sequenceDf = this.statsDf.groupBy(columns)
445
434
  .where('pValue <= 0.1')
@@ -465,8 +454,8 @@ export class PeptidesModel {
465
454
  createGrids(
466
455
  matrixDf: DG.DataFrame, positionColumns: string[], sequenceDf: DG.DataFrame, alphabet: string): DG.Grid[] {
467
456
  const sarGrid = matrixDf.plot.grid();
468
- sarGrid.sort([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]);
469
- sarGrid.columns.setOrder([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE].concat(positionColumns as C.COLUMNS_NAMES[]));
457
+ sarGrid.sort([C.COLUMNS_NAMES.MONOMER]);
458
+ sarGrid.columns.setOrder([C.COLUMNS_NAMES.MONOMER].concat(positionColumns as C.COLUMNS_NAMES[]));
470
459
 
471
460
  const sarVGrid = sequenceDf.plot.grid();
472
461
  sarVGrid.sort([C.COLUMNS_NAMES.POSITION]);
@@ -474,18 +463,18 @@ export class PeptidesModel {
474
463
  pValGridCol.format = '#.000';
475
464
  pValGridCol.name = 'P-value';
476
465
 
477
- let tempCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
466
+ let tempCol = matrixDf.getCol(C.COLUMNS_NAMES.MONOMER);
478
467
  if (tempCol)
479
468
  setAARRenderer(tempCol, alphabet, sarGrid);
480
469
 
481
- tempCol = sequenceDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
470
+ tempCol = sequenceDf.getCol(C.COLUMNS_NAMES.MONOMER);
482
471
  if (tempCol)
483
472
  setAARRenderer(tempCol, alphabet, sarGrid);
484
473
 
485
474
  return [sarGrid, sarVGrid];
486
475
  }
487
476
 
488
- setBarChartInteraction() {
477
+ setBarChartInteraction(): void {
489
478
  const eventAction = (ev: MouseEvent): void => {
490
479
  const cell = this._sourceGrid.hitTest(ev.offsetX, ev.offsetY);
491
480
  if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.MONOMER) {
@@ -495,11 +484,13 @@ export class PeptidesModel {
495
484
  };
496
485
 
497
486
  // The following events makes the barchart interactive
498
- rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'mousemove').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
499
- rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'click').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
487
+ rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'mousemove')
488
+ .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
489
+ rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'click')
490
+ .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
500
491
  }
501
492
 
502
- findAARandPosition(cell: DG.GridCell, ev: MouseEvent) {
493
+ findAARandPosition(cell: DG.GridCell, ev: MouseEvent): {monomer: string, position: string} | null {
503
494
  const barCoords = this.barsBounds[cell.tableColumn!.name];
504
495
  for (const [monomer, coords] of Object.entries(barCoords)) {
505
496
  const isIntersectingX = ev.offsetX >= coords.x && ev.offsetX <= coords.x + coords.width;
@@ -557,11 +548,11 @@ export class PeptidesModel {
557
548
  const gridTable = cell.grid.table;
558
549
  const currentPosition: string = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
559
550
  tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
560
- const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
551
+ const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.MONOMER, tableRowIndex);
561
552
 
562
553
  const viewer = this.getViewer();
563
554
  renderSARCell(canvasContext, currentAAR, currentPosition, this.statsDf, viewer.bidirectionalAnalysis, mdCol,
564
- bound, cellValue, this.currentSelection, viewer.showSubstitution ? this.substitutionsInfo : null);
555
+ bound, cellValue, this.currentSelection, this.substitutionsInfo);
565
556
  }
566
557
  args.preventDefault();
567
558
  }
@@ -597,9 +588,9 @@ export class PeptidesModel {
597
588
  const tableColName = tableCol?.name;
598
589
  const tableRowIndex = cell.tableRowIndex;
599
590
 
600
- if (!cell.isRowHeader && !cell.isColHeader && tableCol && tableRowIndex) {
591
+ if (!cell.isRowHeader && !cell.isColHeader && tableCol && tableRowIndex != null) {
601
592
  const table = cell.grid.table;
602
- const currentAAR = table.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
593
+ const currentAAR = table.get(C.COLUMNS_NAMES.MONOMER, tableRowIndex);
603
594
 
604
595
  if (tableCol.semType == C.SEM_TYPES.MONOMER)
605
596
  this.showMonomerTooltip(currentAAR, x, y);
@@ -667,34 +658,31 @@ export class PeptidesModel {
667
658
  const sarDf = this._sarGrid.dataFrame;
668
659
  const sarVDf = this._sarVGrid.dataFrame;
669
660
 
670
- const chooseAction = (aar: string, position: string, isShiftPressed: boolean) => {
661
+ const chooseAction = (aar: string, position: string, isShiftPressed: boolean): void =>
671
662
  isShiftPressed ? this.modifyCurrentSelection(aar, position) : this.initCurrentSelection(aar, position);
672
- };
673
663
 
674
- const gridCellValidation = (gc: DG.GridCell | null) => !gc || !gc.cell.value || !gc.tableColumn ||
675
- gc.tableRowIndex == null || gc.tableRowIndex == -1;
676
664
  this._sarGrid.root.addEventListener('click', (ev) => {
677
665
  const gridCell = this._sarGrid.hitTest(ev.offsetX, ev.offsetY);
678
- if (gridCellValidation(gridCell) || gridCell!.tableColumn!.name == C.COLUMNS_NAMES.AMINO_ACID_RESIDUE)
666
+ if (isGridCellInvalid(gridCell) || gridCell!.tableColumn!.name == C.COLUMNS_NAMES.MONOMER)
679
667
  return;
680
668
 
681
669
  const position = gridCell!.tableColumn!.name;
682
- const aar = sarDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, gridCell!.tableRowIndex!);
670
+ const aar = sarDf.get(C.COLUMNS_NAMES.MONOMER, gridCell!.tableRowIndex!);
683
671
  chooseAction(aar, position, ev.shiftKey);
684
672
  });
685
673
 
686
674
  this._sarVGrid.root.addEventListener('click', (ev) => {
687
675
  const gridCell = this._sarVGrid.hitTest(ev.offsetX, ev.offsetY);
688
- if (gridCellValidation(gridCell) || gridCell!.tableColumn!.name != C.COLUMNS_NAMES.MEAN_DIFFERENCE)
676
+ if (isGridCellInvalid(gridCell) || gridCell!.tableColumn!.name != C.COLUMNS_NAMES.MEAN_DIFFERENCE)
689
677
  return;
690
678
 
691
679
  const tableRowIdx = gridCell!.tableRowIndex!;
692
680
  const position = sarVDf.get(C.COLUMNS_NAMES.POSITION, tableRowIdx);
693
- const aar = sarVDf.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIdx);
681
+ const aar = sarVDf.get(C.COLUMNS_NAMES.MONOMER, tableRowIdx);
694
682
  chooseAction(aar, position, ev.shiftKey);
695
683
  });
696
684
 
697
- const cellChanged = (table: DG.DataFrame) => {
685
+ const cellChanged = (table: DG.DataFrame): void => {
698
686
  if (this.isCellChanging)
699
687
  return;
700
688
  this.isCellChanging = true;
@@ -749,7 +737,7 @@ export class PeptidesModel {
749
737
  return;
750
738
  }
751
739
 
752
- const updateEdfSelection = () => {
740
+ const updateEdfSelection = (): void => {
753
741
  this.isChangingEdfBitset = true;
754
742
  edfSelection?.copyFrom(currentBitset);
755
743
  this.isChangingEdfBitset = false;
@@ -763,7 +751,7 @@ export class PeptidesModel {
763
751
  }
764
752
 
765
753
  //TODO: move out
766
- const getBitAt = (i: number) => {
754
+ const getBitAt = (i: number): boolean => {
767
755
  for (const position of positionList) {
768
756
  const positionCol: DG.Column<string> = this.df.getCol(position);
769
757
  if (this._currentSelection[position].includes(positionCol.get(i)!))
@@ -800,14 +788,14 @@ export class PeptidesModel {
800
788
  for (let i = 0; i < colNum; ++i) {
801
789
  const col = girdCols.byIndex(i)!;
802
790
  const colName = col.name;
803
- if (grid == sarVGrid && colName !== 'Diff' && colName !== C.COLUMNS_NAMES.AMINO_ACID_RESIDUE)
791
+ if (grid == sarVGrid && colName !== 'Diff' && colName !== C.COLUMNS_NAMES.MONOMER)
804
792
  col.width = 50;
805
793
  else
806
794
  col.width = gridProps.rowHeight + 10;
807
795
  }
808
796
  }
809
797
 
810
- const setViewerGridProps = (grid: DG.Grid) => {
798
+ const setViewerGridProps = (grid: DG.Grid): void => {
811
799
  grid.props.allowEdit = false;
812
800
  grid.props.allowRowSelection = false;
813
801
  grid.props.allowBlockSelection = false;
@@ -853,7 +841,7 @@ export class PeptidesModel {
853
841
  return;
854
842
 
855
843
  this.monomerLib =
856
- JSON.parse(await grok.functions.call('Helm:getMonomerLib', {type: this.df.getTag('monomerType')}));
844
+ JSON.parse(await grok.functions.call('Helm:getMonomerLib', {type: this.df.getTag('monomerType')}) as string);
857
845
 
858
846
  this.currentView = this.df.tags[C.PEPTIDES_ANALYSIS] == 'true' ? grok.shell.v as DG.TableView :
859
847
  grok.shell.addTableView(this.df);
@@ -864,6 +852,7 @@ export class PeptidesModel {
864
852
  this.df.tags[C.PEPTIDES_ANALYSIS] = 'true';
865
853
  this._sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!.name = this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED];
866
854
  this._sourceGrid.columns.setOrder([this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED]]);
855
+ this._sourceGrid.props.allowColSelection = false;
867
856
 
868
857
  this.df.temp[C.EMBEDDING_STATUS] = false;
869
858
  const adjustCellSize = (grid: DG.Grid): void => {
@@ -893,15 +882,18 @@ export class PeptidesModel {
893
882
 
894
883
  const sarViewersGroup: viewerTypes[] = [this.sarViewer, this.sarViewerVertical];
895
884
 
896
- if (this.df.rowCount <= 10000) {
897
- const peptideSpaceViewerOptions = {method: 'UMAP', measure: 'Levenshtein', cyclesCount: 100};
898
- const peptideSpaceViewer =
899
- await this.df.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
900
- dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space Viewer');
901
- }
885
+ // TODO: completely remove this viewer?
886
+ // if (this.df.rowCount <= 10000) {
887
+ // const peptideSpaceViewerOptions = {method: 'UMAP', measure: 'Levenshtein', cyclesCount: 100};
888
+ // const peptideSpaceViewer =
889
+ // await this.df.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
890
+ // dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space Viewer');
891
+ // }
902
892
 
903
893
  this.updateDefault();
904
894
 
895
+ this.currentView.filters({filters: [{type: 'Peptides:invariantMapFilter'}]});
896
+
905
897
  dockViewers(sarViewersGroup, DG.DOCK_TYPE.RIGHT, dockManager, DG.DOCK_TYPE.DOWN);
906
898
 
907
899
  this._sourceGrid.props.allowEdit = false;
@@ -11,7 +11,6 @@ export {tests};
11
11
  //input: string category {optional: true}
12
12
  //input: string test {optional: true}
13
13
  //output: dataframe result
14
- //top-menu: Tools | Dev | JS API Tests
15
14
  export async function test(category: string, test: string): Promise<DG.DataFrame> {
16
15
  const data = await runTests({category, test: test});
17
16
  return DG.DataFrame.fromObjects(data)!;
package/src/package.ts CHANGED
@@ -11,7 +11,7 @@ import {manualAlignmentWidget} from './widgets/manual-alignment';
11
11
  import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
12
12
 
13
13
  import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
14
- import {getSeparator} from './utils/misc';
14
+ import {InvariantMap} from './utils/invariant-map';
15
15
 
16
16
  export const _package = new DG.Package();
17
17
  let currentTable: DG.DataFrame;
@@ -124,28 +124,6 @@ export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
124
124
  return widget.draw();
125
125
  }
126
126
 
127
- /*
128
- //name: Molfile
129
- //tags: panel, widgets
130
- //input: string peptide {semType: Macromolecule}
131
- //output: widget result
132
- export async function peptideMolfile(peptide: string): Promise<DG.Widget> {
133
- [currentTable, alignedSequenceColumn] = getOrDefine();
134
- const smiles = getMolecule(peptide, getSeparator(alignedSequenceColumn));
135
- return grok.functions.call('Chem:molfile', {'smiles': smiles}) as Promise<DG.Widget>;
136
- }
137
-
138
- //name: Molfile
139
- //tags: panel, widgets
140
- //input: string _aar {semType: Monomer}
141
- //output: widget result
142
- export async function peptideMolfile2(_aar: string): Promise<DG.Widget> {
143
- [currentTable, alignedSequenceColumn] = getOrDefine();
144
- const peptide = alignedSequenceColumn.get(currentTable.currentRowIdx);
145
- return peptideMolfile(peptide);
146
- }
147
- */
148
-
149
127
  //name: Get Peptides Structure
150
128
  //tags: panel, widgets
151
129
  //input: column col {semType: Macromolecule}
@@ -176,3 +154,10 @@ function getOrDefine(dataframe?: DG.DataFrame, column?: DG.Column | null): [DG.D
176
154
 
177
155
  return [dataframe, column];
178
156
  }
157
+
158
+ //name: Invariant Map Filter
159
+ //tags: filter
160
+ //output: filter result
161
+ export function invariantMapFilter() {
162
+ return new InvariantMap();
163
+ }
package/src/tests/core.ts CHANGED
@@ -31,10 +31,13 @@ category('Core', () => {
31
31
  simpleActivityCol = simpleTable.getCol(simpleActivityColName);
32
32
  simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
33
33
  simpleAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
34
+ simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
35
+ simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
36
+ simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
34
37
  [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
35
38
 
36
39
  model = await startAnalysis(
37
- simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName, _package);
40
+ simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName);
38
41
  expect(model instanceof PeptidesModel, true);
39
42
 
40
43
  if (model != null) {
@@ -49,10 +52,14 @@ category('Core', () => {
49
52
  complexActivityCol = complexTable.getCol(complexActivityColName);
50
53
  complexAlignedSeqCol = complexTable.getCol('MSA');
51
54
  complexAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
55
+ complexAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'UN';
56
+ complexAlignedSeqCol.tags[DG.TAGS.UNITS] = 'separator';
57
+ complexAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
58
+ complexAlignedSeqCol.tags[C.TAGS.SEPARATOR] = '/';
52
59
  [complexScaledDf, complexScaledColName] = scaleActivity('-lg', complexTable, complexActivityColName, true);
53
60
 
54
61
  model = await startAnalysis(
55
- complexActivityCol, complexAlignedSeqCol, complexTable, complexScaledDf, complexScaledColName, _package);
62
+ complexActivityCol, complexAlignedSeqCol, complexTable, complexScaledDf, complexScaledColName);
56
63
  expect(model instanceof PeptidesModel, true);
57
64
 
58
65
  if (model != null) {
@@ -67,10 +74,13 @@ category('Core', () => {
67
74
  simpleActivityCol = simpleTable.getCol(simpleActivityColName);
68
75
  simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
69
76
  simpleAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
77
+ simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
78
+ simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
79
+ simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
70
80
  [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
71
81
 
72
82
  model = await startAnalysis(
73
- simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName, _package);
83
+ simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName);
74
84
  let v = grok.shell.getTableView('Peptides analysis');
75
85
  const d = v.dataFrame;
76
86
  const layout = v.saveLayout();
@@ -62,27 +62,27 @@ category('Peptide Space Performance', () => {
62
62
  test('test_compute_weights_performance', async () => {
63
63
  const table = DG.DataFrame.fromCsv(await _package.files.readAsText('peptides_large.csv'));
64
64
  const results: {[key: string]: {[key: string]: {[key: string]: number}}} = {};
65
- const slice_volumes = [1, 2, 3, 4, 5, 7, 10];
65
+ const sliceVolumes = [1, 2, 3, 4, 5, 7, 10];
66
66
  const methods = DimensionalityReducer.availableMethods;
67
67
  const metrics = DimensionalityReducer.availableMetricsByType('String');
68
- const total_runs = slice_volumes.length * methods.length * metrics.length;
68
+ const totalRuns = sliceVolumes.length * methods.length * metrics.length;
69
69
  console.log('Started Peptide Space Performance benchmark...');
70
70
 
71
71
  let run = 0;
72
- for (const slice of slice_volumes) {
72
+ for (const slice of sliceVolumes) {
73
73
  const bitset = DG.BitSet.create(table.rowCount, (i) => i < slice * 1000);
74
- const table_slice = table.clone(bitset);
75
- const col = table_slice.getCol('sequence');
74
+ const tableSlice = table.clone(bitset);
75
+ const col = tableSlice.getCol('sequence');
76
76
  const methodObj: {[key: string]: {[key: string]: number}} = {};
77
77
 
78
78
  for (const method of methods) {
79
79
  const measureObj: {[key: string]: number} = {};
80
80
 
81
81
  for (const metric of metrics) {
82
- console.log(`Run ${run++}/${total_runs}`);
82
+ console.log(`Run ${run++}/${totalRuns}`);
83
83
 
84
84
  const start = new Date();
85
- await computeWeights(table_slice, method, metric, 100, col);
85
+ await computeWeights(tableSlice, method, metric, 100, col);
86
86
  const stop = new Date();
87
87
 
88
88
  measureObj[metric] = stop.getTime() - start.getTime();