@datagrok/peptides 1.2.0 → 1.3.1

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/package.ts CHANGED
@@ -5,13 +5,13 @@ import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import * as C from './utils/constants';
7
7
 
8
- import {analyzePeptidesWidget} from './widgets/analyze-peptides';
8
+ import {analyzePeptidesWidget} from './widgets/peptides';
9
9
  import {PeptideSimilaritySpaceWidget} from './utils/peptide-similarity-space';
10
10
  import {manualAlignmentWidget} from './widgets/manual-alignment';
11
- import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
11
+ import {MutationCliffsViewer, MostPotentResiduesViewer} from './viewers/sar-viewer';
12
12
 
13
13
  import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
14
- import {InvariantMap} from './utils/invariant-map';
14
+ import {LogoSummary} from './viewers/logo-summary';
15
15
 
16
16
  export const _package = new DG.Package();
17
17
  let currentTable: DG.DataFrame;
@@ -84,16 +84,23 @@ export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
84
84
  //description: Peptides SAR Viewer
85
85
  //tags: viewer
86
86
  //output: viewer result
87
- export function sar(): SARViewer {
88
- return new SARViewer();
87
+ export function sar(): MutationCliffsViewer {
88
+ return new MutationCliffsViewer();
89
89
  }
90
90
 
91
91
  //name: peptide-sar-viewer-vertical
92
92
  //description: Peptides Vertical SAR Viewer
93
93
  //tags: viewer
94
94
  //output: viewer result
95
- export function sarVertical(): SARViewerVertical {
96
- return new SARViewerVertical();
95
+ export function sarVertical(): MostPotentResiduesViewer {
96
+ return new MostPotentResiduesViewer();
97
+ }
98
+
99
+ //name: logo-summary-viewer
100
+ //tags: viewer
101
+ //output: viewer result
102
+ export function logoSummary(): LogoSummary {
103
+ return new LogoSummary();
97
104
  }
98
105
 
99
106
  //name: peptide-space-viewer
@@ -148,16 +155,10 @@ export function getPeptidesStructure(col: DG.Column): DG.Widget {
148
155
 
149
156
  function getOrDefine(dataframe?: DG.DataFrame, column?: DG.Column | null): [DG.DataFrame, DG.Column] {
150
157
  dataframe ??= grok.shell.t;
151
- column ??= dataframe.columns.bySemType(C.SEM_TYPES.MACROMOLECULE);
158
+ // column ??= dataframe.columns.bySemType(C.SEM_TYPES.MACROMOLECULE);
159
+ column ??= dataframe.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
152
160
  if (column === null)
153
161
  throw new Error('Table does not contain aligned sequence columns');
154
162
 
155
163
  return [dataframe, column];
156
164
  }
157
-
158
- //name: Invariant Map Filter
159
- //tags: filter
160
- //output: filter result
161
- export function invariantMapFilter() {
162
- return new InvariantMap();
163
- }
package/src/styles.css CHANGED
@@ -51,4 +51,5 @@
51
51
  font-family: 'Roboto', 'Roboto Local', sans-serif;
52
52
  color: #4D5261;
53
53
  text-align: center;
54
+ width: 100%;
54
55
  }
package/src/tests/core.ts CHANGED
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
  import {category, test, expect, delay} from '@datagrok-libraries/utils/src/test';
5
5
 
6
6
  import {_package} from '../package-test';
7
- import {startAnalysis} from '../widgets/analyze-peptides';
7
+ import {startAnalysis} from '../widgets/peptides';
8
8
  import {PeptidesModel} from '../model';
9
9
  import * as C from '../utils/constants';
10
10
  import {scaleActivity} from '../utils/misc';
@@ -14,6 +14,7 @@ category('Core', () => {
14
14
  let simpleActivityCol: DG.Column<number>;
15
15
  let simpleAlignedSeqCol: DG.Column<string>;
16
16
  let simpleScaledDf: DG.DataFrame;
17
+ let scalingFormula: (x: number) => number;
17
18
  let simpleScaledColName: string;
18
19
 
19
20
  let complexTable: DG.DataFrame;
@@ -34,14 +35,14 @@ category('Core', () => {
34
35
  simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
35
36
  simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
36
37
  simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
37
- [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
38
+ [simpleScaledDf, scalingFormula, simpleScaledColName] = scaleActivity('-lg', simpleActivityCol);
38
39
 
39
40
  model = await startAnalysis(
40
- simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName);
41
+ simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, scalingFormula, simpleScaledColName, '-lg', []);
41
42
  expect(model instanceof PeptidesModel, true);
42
43
 
43
44
  if (model != null) {
44
- model.currentSelection = {'11': ['D']};
45
+ model.mutationCliffsSelection = {'11': ['D']};
45
46
  grok.shell.closeTable(model.df);
46
47
  }
47
48
  });
@@ -56,14 +57,14 @@ category('Core', () => {
56
57
  complexAlignedSeqCol.tags[DG.TAGS.UNITS] = 'separator';
57
58
  complexAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
58
59
  complexAlignedSeqCol.tags[C.TAGS.SEPARATOR] = '/';
59
- [complexScaledDf, complexScaledColName] = scaleActivity('-lg', complexTable, complexActivityColName, true);
60
+ [complexScaledDf, scalingFormula, complexScaledColName] = scaleActivity('-lg', complexActivityCol);
60
61
 
61
62
  model = await startAnalysis(
62
- complexActivityCol, complexAlignedSeqCol, complexTable, complexScaledDf, complexScaledColName);
63
+ complexActivityCol, complexAlignedSeqCol, null, complexTable, scalingFormula, complexScaledColName, '-lg', []);
63
64
  expect(model instanceof PeptidesModel, true);
64
65
 
65
66
  if (model != null) {
66
- model.currentSelection = {'13': ['-']};
67
+ model.mutationCliffsSelection = {'13': ['-']};
67
68
  grok.shell.closeTable(model.df);
68
69
  }
69
70
  });
@@ -77,10 +78,10 @@ category('Core', () => {
77
78
  simpleAlignedSeqCol.tags[C.TAGS.ALPHABET] = 'PT';
78
79
  simpleAlignedSeqCol.tags[DG.TAGS.UNITS] = 'fasta';
79
80
  simpleAlignedSeqCol.tags['aligned'] = 'SEQ.MSA';
80
- [simpleScaledDf, simpleScaledColName] = scaleActivity('-lg', simpleTable, simpleActivityColName, true);
81
+ [simpleScaledDf, scalingFormula, simpleScaledColName] = scaleActivity('-lg', simpleActivityCol);
81
82
 
82
83
  model = await startAnalysis(
83
- simpleActivityCol, simpleAlignedSeqCol, simpleTable, simpleScaledDf, simpleScaledColName);
84
+ simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, scalingFormula, simpleScaledColName, '-lg', []);
84
85
  let v = grok.shell.getTableView('Peptides analysis');
85
86
  const d = v.dataFrame;
86
87
  const layout = v.saveLayout();
@@ -58,40 +58,40 @@ category('Peptide space', async () => {
58
58
  });
59
59
  });
60
60
 
61
- category('Peptide Space Performance', () => {
62
- test('test_compute_weights_performance', async () => {
63
- const table = DG.DataFrame.fromCsv(await _package.files.readAsText('peptides_large.csv'));
64
- const results: {[key: string]: {[key: string]: {[key: string]: number}}} = {};
65
- const sliceVolumes = [1, 2, 3, 4, 5, 7, 10];
66
- const methods = DimensionalityReducer.availableMethods;
67
- const metrics = DimensionalityReducer.availableMetricsByType('String');
68
- const totalRuns = sliceVolumes.length * methods.length * metrics.length;
69
- console.log('Started Peptide Space Performance benchmark...');
61
+ // category('Peptide Space Performance', () => {
62
+ // test('test_compute_weights_performance', async () => {
63
+ // const table = DG.DataFrame.fromCsv(await _package.files.readAsText('peptides_large.csv'));
64
+ // const results: {[key: string]: {[key: string]: {[key: string]: number}}} = {};
65
+ // const sliceVolumes = [1, 2, 3, 4, 5, 7, 10];
66
+ // const methods = DimensionalityReducer.availableMethods;
67
+ // const metrics = DimensionalityReducer.availableMetricsByType('String');
68
+ // const totalRuns = sliceVolumes.length * methods.length * metrics.length;
69
+ // console.log('Started Peptide Space Performance benchmark...');
70
70
 
71
- let run = 0;
72
- for (const slice of sliceVolumes) {
73
- const bitset = DG.BitSet.create(table.rowCount, (i) => i < slice * 1000);
74
- const tableSlice = table.clone(bitset);
75
- const col = tableSlice.getCol('sequence');
76
- const methodObj: {[key: string]: {[key: string]: number}} = {};
71
+ // let run = 0;
72
+ // for (const slice of sliceVolumes) {
73
+ // const bitset = DG.BitSet.create(table.rowCount, (i) => i < slice * 1000);
74
+ // const tableSlice = table.clone(bitset);
75
+ // const col = tableSlice.getCol('sequence');
76
+ // const methodObj: {[key: string]: {[key: string]: number}} = {};
77
77
 
78
- for (const method of methods) {
79
- const measureObj: {[key: string]: number} = {};
78
+ // for (const method of methods) {
79
+ // const measureObj: {[key: string]: number} = {};
80
80
 
81
- for (const metric of metrics) {
82
- console.log(`Run ${run++}/${totalRuns}`);
81
+ // for (const metric of metrics) {
82
+ // console.log(`Run ${run++}/${totalRuns}`);
83
83
 
84
- const start = new Date();
85
- await computeWeights(tableSlice, method, metric, 100, col);
86
- const stop = new Date();
84
+ // const start = new Date();
85
+ // await computeWeights(tableSlice, method, metric, 100, col);
86
+ // const stop = new Date();
87
87
 
88
- measureObj[metric] = stop.getTime() - start.getTime();
89
- }
90
- methodObj[method] = measureObj;
91
- }
92
- results[`${slice}k`] = methodObj;
93
- }
94
- console.log('Peptide Space Performance benchmark finished...');
95
- console.log(results);
96
- });
97
- });
88
+ // measureObj[metric] = stop.getTime() - start.getTime();
89
+ // }
90
+ // methodObj[method] = measureObj;
91
+ // }
92
+ // results[`${slice}k`] = methodObj;
93
+ // }
94
+ // console.log('Peptide Space Performance benchmark finished...');
95
+ // console.log(results);
96
+ // });
97
+ // });
@@ -5,65 +5,24 @@ import * as C from './constants';
5
5
  import {getPalleteByType} from './misc';
6
6
  import * as types from './types';
7
7
 
8
- /**
9
- * A function to expand column size based on its contents.
10
- *
11
- * @export
12
- * @param {DG.Column} col Column to expand.
13
- * @param {DG.Grid} grid Grid containing colum for expansion.
14
- * @param {(cellVal: string) => number} cellRenderSize An anonymous function that calculates cell value length.
15
- * @param {number} [textSizeMult=10] Text size muliplier.
16
- * @param {number} [minSize=30] Minimal column width.
17
- * @param {number} [maxSize=650] Maximum column width.
18
- * @param {number} [timeout=500] Timeout value.
19
- */
20
- export function expandColumn(col: DG.Column, grid: DG.Grid, cellRenderSize: (cellVal: string) => number,
21
- textSizeMult = 10, minSize = 30, maxSize = 650, timeout = 500): void {
22
- let maxLen = 0;
23
- col.categories.forEach((ent: string) => {
24
- const len = cellRenderSize(ent);
25
- if (len > maxLen)
26
- maxLen = len;
27
- });
28
- setTimeout(() => {
29
- grid.columns.byName(col.name)!.width = Math.min(Math.max(maxLen * textSizeMult, minSize), maxSize);
30
- },
31
- timeout);
8
+ function renderCellSelection(canvasContext: CanvasRenderingContext2D, bound: DG.Rect): void {
9
+ canvasContext.strokeStyle = '#000';
10
+ canvasContext.lineWidth = 1;
11
+ canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
32
12
  }
33
13
 
34
- /**
35
- * A function that sets amino acid residue to the specified column.
36
- *
37
- * @export
38
- * @param {DG.Column} col Column to set renderer for.
39
- * @param {(DG.Grid | null)} [grid=null] Grid that contains the col column.
40
- * @param {boolean} [grouping=false] Is grouping enabled.
41
- */
42
- export function setAARRenderer(col: DG.Column, alphabet: string, grid?: DG.Grid): void {
14
+ /** A function that sets amino acid residue cell renderer to the specified column */
15
+ export function setAARRenderer(col: DG.Column, alphabet: string, grid: DG.Grid, timeout: number = 500): void {
43
16
  col.semType = C.SEM_TYPES.MONOMER;
44
17
  col.setTag('cell.renderer', C.SEM_TYPES.MONOMER);
45
18
  col.tags[C.TAGS.ALPHABET] = alphabet;
46
-
47
- if (grid)
48
- expandColumn(col, grid, (ent) => measureAAR(ent));
49
- }
50
-
51
- /**
52
- * A function to measure amino acid residue
53
- *
54
- * @export
55
- * @param {string} s Amino acid residue string.
56
- * @return {number} Amino acid residue size.
57
- */
58
- export function measureAAR(s: string): number {
59
- const end = s.lastIndexOf(')');
60
- const beg = s.indexOf('(');
61
- return end == beg ? s.length : s.length - (end - beg) + 1;
19
+ setTimeout(() => grid.columns.byName(col.name)!.width = 60, timeout);
62
20
  }
63
21
 
64
- export function renderSARCell(canvasContext: CanvasRenderingContext2D, currentAAR: string, currentPosition: string,
65
- statsDf: DG.DataFrame, twoColorMode: boolean, mdCol: DG.Column<number>, bound: DG.Rect, cellValue: number,
66
- currentSelection: types.SelectionObject, substitutionsInfo: types.SubstitutionsInfo): void {
22
+ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
23
+ currentPosition: string, statsDf: DG.DataFrame, twoColorMode: boolean, mdCol: DG.Column<number>, bound: DG.Rect,
24
+ cellValue: number, mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.SubstitutionsInfo,
25
+ ): void {
67
26
  const queryAAR = `${C.COLUMNS_NAMES.MONOMER} = ${currentAAR}`;
68
27
  const query = `${queryAAR} and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
69
28
  const pVal: number = statsDf
@@ -112,13 +71,34 @@ export function renderSARCell(canvasContext: CanvasRenderingContext2D, currentAA
112
71
  canvasContext.fillText(substValue.toString(), midX, midY);
113
72
  }
114
73
 
115
- //TODO: frame based on currentSelection
116
- const aarSelection = currentSelection[currentPosition];
117
- if (aarSelection && aarSelection.includes(currentAAR)) {
118
- canvasContext.strokeStyle = '#000';
119
- canvasContext.lineWidth = 1;
120
- canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
121
- }
74
+ const aarSelection = mutationCliffsSelection[currentPosition];
75
+ if (aarSelection && aarSelection.includes(currentAAR))
76
+ renderCellSelection(canvasContext, bound);
77
+ }
78
+
79
+ export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
80
+ currentPosition: string, invariantMapSelection: types.PositionToAARList, cellValue: number, bound: DG.Rect): void {
81
+ canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
82
+ canvasContext.textAlign = 'center';
83
+ canvasContext.textBaseline = 'middle';
84
+ canvasContext.fillStyle = '#000';
85
+ canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
86
+
87
+ const aarSelection = invariantMapSelection[currentPosition];
88
+ if (aarSelection && aarSelection.includes(currentAAR))
89
+ renderCellSelection(canvasContext, bound);
90
+ }
91
+
92
+ export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, cellValue: number,
93
+ clusterSelection: number[], bound: DG.Rect): void {
94
+ canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
95
+ canvasContext.textAlign = 'center';
96
+ canvasContext.textBaseline = 'middle';
97
+ canvasContext.fillStyle = '#000';
98
+ canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
99
+
100
+ if (clusterSelection.includes(cellValue))
101
+ renderCellSelection(canvasContext, bound);
122
102
  }
123
103
 
124
104
  export function renderBarchart(ctx: CanvasRenderingContext2D, col: DG.Column, monomerColStats: types.MonomerColStats,
@@ -9,6 +9,8 @@ export enum COLUMNS_NAMES {
9
9
  MEAN_DIFFERENCE = 'Mean difference',
10
10
  COUNT = 'Count',
11
11
  RATIO = 'Ratio',
12
+ CLUSTERS = 'clusters',
13
+ MACROMOLECULE = 'macromolecule',
12
14
  }
13
15
 
14
16
  export enum CATEGORIES {
@@ -17,11 +19,16 @@ export enum CATEGORIES {
17
19
  }
18
20
 
19
21
  export enum TAGS {
20
- AAR = 'AAR',
21
- POSITION = 'Pos',
22
+ MONOMER = 'monomer',
23
+ POSITION = 'pos',
22
24
  SEPARATOR = 'separator',
23
25
  SELECTION = 'selection',
24
26
  ALPHABET = 'alphabet',
27
+ FILTER = 'filter',
28
+ CLUSTERS = 'clusters',
29
+ SAR_MODE = 'sarMode',
30
+ CLUSTER_SELECTION = 'clusterSelection',
31
+ VISIBLE = 'visible',
25
32
  }
26
33
 
27
34
  export enum SEM_TYPES {
package/src/utils/misc.ts CHANGED
@@ -32,38 +32,33 @@ export function getSeparator(col: DG.Column<string>): string {
32
32
  return col.getTag(C.TAGS.SEPARATOR) ?? '';
33
33
  }
34
34
 
35
- export function scaleActivity(
36
- activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
37
- ): [DG.DataFrame, string] {
38
- let currentActivityColName = originalActivityName ?? C.COLUMNS_NAMES.ACTIVITY;
39
- const flag = df.columns.names().includes(currentActivityColName) &&
40
- currentActivityColName === originalActivityName;
41
- currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
42
- const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
35
+ export function scaleActivity(activityScaling: string, activityCol: DG.Column<number>, indexes?: number[],
36
+ ): [DG.DataFrame, (x: number) => number, string] {
37
+ const tempDf = DG.DataFrame.create(activityCol.length);
43
38
 
44
- let formula = (v: number): number => v;
39
+ let formula = (x: number): number => x;
45
40
  let newColName = 'activity';
46
41
  switch (activityScaling) {
47
42
  case 'none':
48
43
  break;
49
44
  case 'lg':
50
- formula = (v: number): number => Math.log10(v);
45
+ formula = (x: number): number => Math.log10(x);
51
46
  newColName = `Log10(${newColName})`;
52
47
  break;
53
48
  case '-lg':
54
- formula = (v: number): number => -Math.log10(v);
49
+ formula = (x: number): number => -Math.log10(x);
55
50
  newColName = `-Log10(${newColName})`;
56
51
  break;
57
52
  default:
58
53
  throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
59
54
  }
55
+ tempDf.columns.addNewVirtual(
56
+ C.COLUMNS_NAMES.ACTIVITY_SCALED, (i) => {
57
+ const val = activityCol.get(indexes ? indexes[i] : i);
58
+ return val ? formula(val) : val;
59
+ }, DG.TYPE.FLOAT);
60
60
 
61
- const asCol = tempDf.columns.addNewFloat(C.COLUMNS_NAMES.ACTIVITY_SCALED);
62
- const activityCol = df.getCol(currentActivityColName);
63
- asCol.init((i) => formula(activityCol.get(i)));
64
- df.tags['scaling'] = activityScaling;
65
-
66
- return [tempDf, newColName];
61
+ return [tempDf, formula, newColName];
67
62
  }
68
63
 
69
64
  export function calculateBarsData(columns: DG.Column<string>[], selection: DG.BitSet): type.MonomerDfStats {
@@ -44,7 +44,8 @@ export async function createPeptideSimilaritySpaceViewer(
44
44
  const pi = DG.TaskBarProgressIndicator.create('Creating embedding...');
45
45
 
46
46
  const axesNames = ['~X', '~Y', '~MW'];
47
- col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
47
+ // col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
48
+ col ??= table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
48
49
  const columnData = col.toList().map((v) => AlignedSequenceEncoder.clean(v));
49
50
 
50
51
  const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
@@ -5,7 +5,7 @@ export type DataFrameDict = {[key: string]: DG.DataFrame};
5
5
  export type UTypedArray = Uint8Array | Uint16Array | Uint32Array;
6
6
  //AAR: (Position: (index: indexList))
7
7
  export type SubstitutionsInfo = Map<string, Map<string, Map<number, number[] | UTypedArray>>>;
8
- export type SelectionObject = {[postiton: string]: string[]};
8
+ export type PositionToAARList = {[postiton: string]: string[]};
9
9
 
10
10
  export type HELMMonomer = {at: {[key: string]: string}, id: string, m: string, na: string, n: string, rs: number};
11
11
 
@@ -0,0 +1,42 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as DG from 'datagrok-api/dg';
3
+
4
+ import $ from 'cash-dom';
5
+ import {PeptidesModel} from '../model';
6
+
7
+ export class LogoSummary extends DG.JsViewer {
8
+ _titleHost = ui.divText('Logo Summary Table', {id: 'pep-viewer-title'});
9
+ model!: PeptidesModel;
10
+ viewerGrid!: DG.Grid;
11
+ initialized: boolean = false;
12
+
13
+ constructor() {
14
+ super();
15
+ }
16
+
17
+ async onTableAttached(): Promise<void> {
18
+ super.onTableAttached();
19
+
20
+ this.model = await PeptidesModel.getInstance(this.dataFrame);
21
+
22
+ this.subs.push(this.model.onLogoSummaryGridChanged.subscribe((grid) => {
23
+ this.viewerGrid = grid;
24
+ this.render();
25
+ }));
26
+ this.model.updateDefault();
27
+ this.viewerGrid = this.model.logoSummaryGrid;
28
+ this.initialized = true;
29
+ this.render();
30
+ }
31
+
32
+ detach(): void {this.subs.forEach((sub) => sub.unsubscribe());}
33
+
34
+ render(): void {
35
+ if (this.initialized) {
36
+ $(this.root).empty();
37
+ this.viewerGrid.root.style.width = 'auto';
38
+ this.root.appendChild(ui.divV([this._titleHost, this.viewerGrid.root]));
39
+ this.viewerGrid.invalidate();
40
+ }
41
+ }
42
+ }
@@ -61,8 +61,9 @@ export class PeptideSpaceViewer extends DG.JsViewer {
61
61
  this.isEmbeddingCreating = true;
62
62
  $(this.root).empty();
63
63
  const viewerHost = ui.waitBox(async () => {
64
- const aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
65
- const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, aligendSeqCol);
64
+ // const aligendSeqCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
65
+ const alignedSeqCol = this.dataFrame.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
66
+ const edf = await computeWeights(this.dataFrame, this.method, this.measure, this.cyclesCount, alignedSeqCol);
66
67
  this.dataFrame.temp[C.EMBEDDING_STATUS] = true;
67
68
  this.model.edf = edf;
68
69
 
@@ -92,7 +93,7 @@ export class PeptideSpaceViewer extends DG.JsViewer {
92
93
  if (idx != -1) {
93
94
  const table = ui.tableFromMap({
94
95
  'Activity': colorCol.get(idx),
95
- 'Sequence': aligendSeqCol.get(idx),
96
+ 'Sequence': alignedSeqCol.get(idx),
96
97
  'Row ID': idx,
97
98
  });
98
99
  ui.tooltip.show(table, ev.clientX, ev.clientY);
@@ -117,7 +118,8 @@ export async function computeWeights(
117
118
  let edf: DG.DataFrame | null = null;
118
119
  try {
119
120
  const axesNames = ['~X', '~Y', '~MW'];
120
- col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
121
+ // col ??= table.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
122
+ col ??= table.getCol(C.COLUMNS_NAMES.MACROMOLECULE);
121
123
  const columnData = col.toList().map((v) => AlignedSequenceEncoder.clean(v));
122
124
 
123
125
  const reduceDimRes: IReduceDimensionalityResult = await createDimensinalityReducingWorker(
@@ -20,6 +20,8 @@ export class SARViewerBase extends DG.JsViewer {
20
20
  _titleHost = ui.divText('SAR Viewer', {id: 'pep-viewer-title'});
21
21
  initialized = false;
22
22
  isPropertyChanging: boolean = false;
23
+ _isVertical = false;
24
+ isModeChanging = false;
23
25
 
24
26
  constructor() {
25
27
  super();
@@ -30,6 +32,8 @@ export class SARViewerBase extends DG.JsViewer {
30
32
  this.minActivityDelta = this.float('minActivityDelta', 0);
31
33
  }
32
34
 
35
+ get name(): string {return '';}
36
+
33
37
  async onTableAttached(): Promise<void> {
34
38
  super.onTableAttached();
35
39
  this.sourceGrid = this.view?.grid ?? (grok.shell.v as DG.TableView).grid;
@@ -49,14 +53,56 @@ export class SARViewerBase extends DG.JsViewer {
49
53
 
50
54
  detach(): void {this.subs.forEach((sub) => sub.unsubscribe());}
51
55
 
56
+ get state(): string {
57
+ return this.dataFrame.getTag(C.TAGS.SAR_MODE) ?? '10';
58
+ }
59
+ set state(s: string) {
60
+ this.dataFrame.setTag(C.TAGS.SAR_MODE, s);
61
+ }
62
+
52
63
  render(refreshOnly = false): void {
53
64
  if (!this.initialized)
54
65
  return;
55
66
  if (!refreshOnly) {
56
67
  $(this.root).empty();
68
+ let switchHost = ui.div();
69
+ if (this.name == 'MC') {
70
+ const mutationCliffsMode = ui.boolInput('', this.state[0] === '1', () => {
71
+ if (this.isModeChanging)
72
+ return;
73
+ this.isModeChanging = true;
74
+ invariantMapMode.value = !invariantMapMode.value;
75
+ this.isModeChanging = false;
76
+ this._titleHost.innerText = 'Mutation Cliffs';
77
+ this.model.isInvariantMap = false;
78
+ this.viewerGrid.invalidate();
79
+ });
80
+ mutationCliffsMode.addPostfix('Mutation Cliffs');
81
+ const invariantMapMode = ui.boolInput('', this.state[1] === '1', () => {
82
+ if (this.isModeChanging)
83
+ return;
84
+ this.isModeChanging = true;
85
+ mutationCliffsMode.value = !mutationCliffsMode.value;
86
+ this.isModeChanging = false;
87
+ this._titleHost.innerText = 'Invariant Map';
88
+ this.model.isInvariantMap = true;
89
+ this.viewerGrid.invalidate();
90
+ });
91
+ invariantMapMode.addPostfix('Invariant Map');
92
+ const setDefaultProperties = (input: DG.InputBase): void => {
93
+ $(input.root).find('.ui-input-editor').css('margin', '0px').attr('type', 'radio');
94
+ $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
95
+ };
96
+ setDefaultProperties(mutationCliffsMode);
97
+ setDefaultProperties(invariantMapMode);
98
+ $(mutationCliffsMode.root).css('padding-right', '10px').css('padding-left', '5px');
99
+
100
+ switchHost = ui.divH([mutationCliffsMode.root, invariantMapMode.root]);
101
+ switchHost.style.position = 'absolute';
102
+ }
57
103
  const viewerRoot = this.viewerGrid.root;
58
104
  viewerRoot.style.width = 'auto';
59
- this.root.appendChild(ui.divV([this._titleHost, viewerRoot]));
105
+ this.root.appendChild(ui.divV([ui.divH([switchHost, this._titleHost]), viewerRoot]));
60
106
  }
61
107
  this.viewerGrid?.invalidate();
62
108
  }
@@ -88,9 +134,10 @@ export class SARViewerBase extends DG.JsViewer {
88
134
  /**
89
135
  * Structure-activity relationship viewer.
90
136
  */
91
- export class SARViewer extends SARViewerBase {
137
+ export class MutationCliffsViewer extends SARViewerBase {
92
138
  _titleHost = ui.divText('Mutation Cliffs', {id: 'pep-viewer-title'});
93
- _name = 'Structure-Activity Relationship';
139
+ _name = 'MC';
140
+ _isVertical = false;
94
141
 
95
142
  constructor() {super();}
96
143
 
@@ -98,26 +145,29 @@ export class SARViewer extends SARViewerBase {
98
145
 
99
146
  async onTableAttached(): Promise<void> {
100
147
  await super.onTableAttached();
101
- this.model.sarViewer ??= this;
148
+ this.model.mutationCliffsViewer ??= this;
102
149
 
103
- this.subs.push(this.model.onSARGridChanged.subscribe((data) => {
150
+ this.subs.push(this.model.onMutationCliffsGridChanged.subscribe((data) => {
104
151
  this.viewerGrid = data;
105
152
  this.render();
106
153
  }));
107
154
 
108
155
  this.model.updateDefault();
109
- this.viewerGrid = this.model._sarGrid;
156
+ this.viewerGrid = this.model.mutationCliffsGrid;
110
157
  this.initialized = true;
111
158
  this.render();
112
159
  }
113
160
 
114
- isInitialized(): DG.Grid {return this.model?._sarGrid;}
161
+ isInitialized(): DG.Grid {return this.model?.mutationCliffsGrid;}
115
162
 
116
163
  //1. debouncing in rxjs; 2. flags?
117
164
  onPropertyChanged(property: DG.Property): void {
118
165
  if (!this.isInitialized() || IS_PROPERTY_CHANGING)
119
166
  return;
120
167
 
168
+ if (property.name == 'invariantMap')
169
+ this._titleHost = ui.divText(property.get(this) ? 'Invariant Map' : 'Mutation Cliffs', {id: 'pep-viewer-title'});
170
+
121
171
  super.onPropertyChanged(property);
122
172
  IS_PROPERTY_CHANGING = true;
123
173
  this.model.syncProperties(true);
@@ -126,9 +176,10 @@ export class SARViewer extends SARViewerBase {
126
176
  }
127
177
 
128
178
  /** Vertical structure activity relationship viewer. */
129
- export class SARViewerVertical extends SARViewerBase {
130
- _name = 'Sequence-Activity relationship';
179
+ export class MostPotentResiduesViewer extends SARViewerBase {
180
+ _name = 'MPR';
131
181
  _titleHost = ui.divText('Most Potent Residues', {id: 'pep-viewer-title'});
182
+ _isVertical = true;
132
183
 
133
184
  constructor() {
134
185
  super();
@@ -138,21 +189,21 @@ export class SARViewerVertical extends SARViewerBase {
138
189
 
139
190
  async onTableAttached(): Promise<void> {
140
191
  await super.onTableAttached();
141
- this.model.sarViewerVertical ??= this;
192
+ this.model.mostPotentResiduesViewer ??= this;
142
193
 
143
- this.subs.push(this.model.onSARVGridChanged.subscribe((data) => {
194
+ this.subs.push(this.model.onMostPotentResiduesGridChanged.subscribe((data) => {
144
195
  this.viewerGrid = data;
145
196
  this.render();
146
197
  }));
147
198
 
148
199
  this.model.updateDefault();
149
- this.viewerGrid = this.model._sarVGrid;
200
+ this.viewerGrid = this.model.mostPotentResiduesGrid;
150
201
 
151
202
  this.initialized = true;
152
203
  this.render();
153
204
  }
154
205
 
155
- isInitialized(): DG.Grid {return this.model?._sarVGrid;}
206
+ isInitialized(): DG.Grid {return this.model?.mostPotentResiduesGrid;}
156
207
 
157
208
  onPropertyChanged(property: DG.Property): void {
158
209
  if (!this.isInitialized() || IS_PROPERTY_CHANGING)