@datagrok/peptides 1.12.0 → 1.13.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
@@ -173,7 +173,7 @@ export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
173
173
  //name: Macromolecule SAR Analysis
174
174
  //description: Macromolecule SAR Analysis demo on peptide sequences in FASTA format
175
175
  //meta.demoPath: Bioinformatics | Macromolecule SAR Analysis
176
- //meta.isDemoScript: True
176
+ //meta.isDemoScript: False
177
177
  export async function macromoleculeSarFastaDemo(): Promise<void> {
178
178
  return macromoleculeSarFastaDemoUI();
179
179
  }
package/src/tests/core.ts CHANGED
@@ -44,10 +44,6 @@ category('Core', () => {
44
44
  overlayInit = true;
45
45
  grok.log.debug('Overlay initialized');
46
46
  });
47
- model!._analysisView!.grid.onBeforeDrawOverlay.subscribe(() => {
48
- overlayInit = false;
49
- grok.log.debug('Overlay is drawing');
50
- });
51
47
 
52
48
  // Ensure grid finished initializing to prevent Unhandled exceptions
53
49
  let accrodionInit = false;
@@ -58,7 +54,7 @@ category('Core', () => {
58
54
  await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
59
55
 
60
56
  model!.mutationCliffsSelection = {'11': ['D']};
61
- }, {skipReason: 'GROK-13790: Unhandled exception'});
57
+ }, {skipReason: 'Ignore unhandled exceptions in tests'});
62
58
 
63
59
  test('Start analysis: сomplex', async () => {
64
60
  const complexActivityColName = 'Activity';
@@ -80,10 +76,6 @@ category('Core', () => {
80
76
  overlayInit = true;
81
77
  grok.log.debug('Overlay initialized');
82
78
  });
83
- model!._analysisView!.grid.onBeforeDrawOverlay.subscribe(() => {
84
- overlayInit = false;
85
- grok.log.debug('Overlay is drawing');
86
- });
87
79
 
88
80
  // Ensure grid finished initializing to prevent Unhandled exceptions
89
81
  let accrodionInit = false;
@@ -95,7 +87,7 @@ category('Core', () => {
95
87
 
96
88
  if (model !== null)
97
89
  model.mutationCliffsSelection = {'13': ['-']};
98
- }, {skipReason: 'GROK-13790: Unhandled exception'});
90
+ }, {skipReason: 'Ignore unhandled exceptions in tests'});
99
91
 
100
92
  test('Save and load project', async () => {
101
93
  const simpleActivityColName = 'IC50';
@@ -3,7 +3,7 @@ import * as DG from 'datagrok-api/dg';
3
3
 
4
4
  import {category, test, before, expect, awaitCheck} from '@datagrok-libraries/utils/src/test';
5
5
  import {_package} from '../package-test';
6
- import {PeptidesModel} from '../model';
6
+ import {CLUSTER_TYPE, PeptidesModel} from '../model';
7
7
  import {startAnalysis} from '../widgets/peptides';
8
8
  import {scaleActivity} from '../utils/misc';
9
9
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
@@ -19,10 +19,10 @@ category('Table view', () => {
19
19
  let scaledActivityCol: DG.Column<number>;
20
20
  const scaling = 'none' as SCALING_METHODS;
21
21
 
22
- const firstPair = {monomer: 'Aze', position: '10', mcCount: 3, imCount: 1};
23
- const secondPair = {monomer: 'meI', position: '1', mcCount: 2, imCount: 10};
24
- const firstCluster = {name: '0', count: 3};
25
- const secondCluster = {name: '1', count: 3};
22
+ const firstPair = {monomerOrCluster: 'Aze', positionOrClusterType: '10', mcCount: 3, imCount: 1};
23
+ const secondPair = {monomerOrCluster: 'meI', positionOrClusterType: '1', mcCount: 2, imCount: 10};
24
+ const firstCluster = {monomerOrCluster: '0', positionOrClusterType: CLUSTER_TYPE.ORIGINAL, count: 3};
25
+ const secondCluster = {monomerOrCluster: '1', positionOrClusterType: CLUSTER_TYPE.ORIGINAL, count: 3};
26
26
 
27
27
  before(async () => {
28
28
  df = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/HELM_small.csv'));
@@ -49,8 +49,8 @@ category('Table view', () => {
49
49
  });
50
50
 
51
51
  test('Tooltip', async () => {
52
- expect(model.showMonomerTooltip(firstPair.monomer, 0, 0), true,
53
- `Couldn't structure for monomer ${firstPair.monomer}`);
52
+ expect(model.showMonomerTooltip(firstPair.monomerOrCluster, 0, 0), true,
53
+ `Couldn't structure for monomer ${firstPair.monomerOrCluster}`);
54
54
  }, {skipReason: 'Need to find a way to replace _package variable to call for Bio function with tests'});
55
55
 
56
56
  test('Visible columns', async () => {
@@ -73,29 +73,29 @@ category('Table view', () => {
73
73
  expect(selectedMonomers.length, 0, `Selection is not empty for position ${position} after initialization`);
74
74
 
75
75
  // Select first monomer-position pair
76
- model.modifyMonomerPositionSelection(firstPair.monomer, firstPair.position, false);
77
- expect(model.mutationCliffsSelection[firstPair.position].includes(firstPair.monomer), true,
78
- `Monomer ${firstPair.monomer} is not selected at position ${firstPair.position}`);
76
+ model.modifyMutationCliffsSelection(firstPair);
77
+ expect(model.mutationCliffsSelection[firstPair.positionOrClusterType].includes(firstPair.monomerOrCluster), true,
78
+ `Monomer ${firstPair.monomerOrCluster} is not selected at position ${firstPair.positionOrClusterType}`);
79
79
  expect(selection.trueCount, firstPair.mcCount, `Selection count is not equal to ${firstPair.mcCount} ` +
80
- `for monomer ${firstPair.monomer} at position ${firstPair.position}`);
80
+ `for monomer ${firstPair.monomerOrCluster} at position ${firstPair.positionOrClusterType}`);
81
81
 
82
82
  // Select second monomer-position pair
83
- model.modifyMonomerPositionSelection(secondPair.monomer, secondPair.position, false);
84
- expect(model.mutationCliffsSelection[secondPair.position].includes(secondPair.monomer), true,
85
- `Monomer ${secondPair.monomer} is not selected at position ${secondPair.position}`);
83
+ model.modifyMutationCliffsSelection(secondPair, {shiftPressed: true, ctrlPressed: false});
84
+ expect(model.mutationCliffsSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), true,
85
+ `Monomer ${secondPair.monomerOrCluster} is not selected at position ${secondPair.positionOrClusterType}`);
86
86
  expect(selection.trueCount, secondPair.mcCount + firstPair.mcCount, `Selection count is not equal ` +
87
- `to ${secondPair.mcCount + firstPair.mcCount} for monomer ${secondPair.monomer} at ` +
88
- `position ${secondPair.position}`);
87
+ `to ${secondPair.mcCount + firstPair.mcCount} for monomer ${secondPair.monomerOrCluster} at ` +
88
+ `position ${secondPair.positionOrClusterType}`);
89
89
 
90
90
  // Deselect second monomer-position pair
91
- model.modifyMonomerPositionSelection(secondPair.monomer, secondPair.position, false);
92
- expect(model.mutationCliffsSelection[secondPair.position].includes(secondPair.monomer), false,
93
- `Monomer ${secondPair.monomer} is still selected at position ${secondPair.position} after deselection`);
91
+ model.modifyMutationCliffsSelection(secondPair, {shiftPressed: true, ctrlPressed: true});
92
+ expect(model.mutationCliffsSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), false,
93
+ `Monomer ${secondPair.monomerOrCluster} is still selected at position ${secondPair.positionOrClusterType} after deselection`);
94
94
  expect(selection.trueCount, firstPair.mcCount, `Selection count is not equal to ${firstPair.mcCount} ` +
95
- `for monomer ${firstPair.monomer} at position ${firstPair.position}`);
95
+ `for monomer ${firstPair.monomerOrCluster} at position ${firstPair.positionOrClusterType}`);
96
96
 
97
97
  // Clear monomer-position selection
98
- model.initMutationCliffsSelection({cleanInit: true});
98
+ model.initMutationCliffsSelection();
99
99
  for (const [position, selectedMonomers] of Object.entries(model.mutationCliffsSelection)) {
100
100
  expect(selectedMonomers.length, 0, `Selection is not empty for position ${position} after clearing ` +
101
101
  `monomer-position selection`);
@@ -103,29 +103,29 @@ category('Table view', () => {
103
103
  expect(selection.trueCount, 0, `Selection count is not equal to 0 after clearing monomer-position selection`);
104
104
 
105
105
  // Select first cluster
106
- model.modifyClusterSelection(firstCluster.name);
107
- expect(model.clusterSelection.includes(firstCluster.name), true,
108
- `Cluster ${firstCluster.name} is not selected`);
106
+ model.modifyClusterSelection(firstCluster);
107
+ expect(model.clusterSelection[firstCluster.positionOrClusterType].includes(firstCluster.monomerOrCluster), true,
108
+ `Cluster ${firstCluster.monomerOrCluster} is not selected`);
109
109
  expect(selection.trueCount, firstCluster.count, `Selection count is not equal to ${firstCluster.count} for ` +
110
- `cluster ${firstCluster.name}`);
110
+ `cluster ${firstCluster.monomerOrCluster}`);
111
111
 
112
112
  // Select second cluster
113
- model.modifyClusterSelection(secondCluster.name);
114
- expect(model.clusterSelection.includes(secondCluster.name), true,
115
- `Cluster ${secondCluster.name} is not selected`);
113
+ model.modifyClusterSelection(secondCluster, {shiftPressed: true, ctrlPressed: false});
114
+ expect(model.clusterSelection[secondCluster.positionOrClusterType].includes(secondCluster.monomerOrCluster), true,
115
+ `Cluster ${secondCluster.monomerOrCluster} is not selected`);
116
116
  expect(selection.trueCount, firstCluster.count + secondCluster.count, `Selection count is not equal to ` +
117
- `${firstCluster.count + secondCluster.count} for cluster ${firstCluster.name} and cluster ${secondCluster.name}`);
117
+ `${firstCluster.count + secondCluster.count} for cluster ${firstCluster.monomerOrCluster} and cluster ${secondCluster.monomerOrCluster}`);
118
118
 
119
119
  // Deselect first cluster
120
- model.modifyClusterSelection(firstCluster.name);
121
- expect(model.clusterSelection.includes(firstCluster.name), false,
122
- `Cluster ${firstCluster.name} is still selected after deselection`);
120
+ model.modifyClusterSelection(firstCluster, {shiftPressed: true, ctrlPressed: true});
121
+ expect(model.clusterSelection[firstCluster.positionOrClusterType].includes(firstCluster.monomerOrCluster), false,
122
+ `Cluster ${firstCluster.monomerOrCluster} is still selected after deselection`);
123
123
  expect(selection.trueCount, secondCluster.count, `Selection count is not equal to ${secondCluster.count} for ` +
124
- `cluster ${secondCluster.name} after deselection of cluster ${firstCluster.name}`);
124
+ `cluster ${secondCluster.monomerOrCluster} after deselection of cluster ${firstCluster.monomerOrCluster}`);
125
125
 
126
126
  // Clear selection
127
127
  model.initClusterSelection();
128
- expect(model.clusterSelection.length, 0, `Selection is not empty after clearing cluster selection`);
128
+ expect(model.isClusterSelectionEmpty, true, `Selection is not empty after clearing cluster selection`);
129
129
  expect(selection.trueCount, 0, `Selection count is not equal to 0 after clearing cluster selection`);
130
130
  });
131
131
 
@@ -136,30 +136,30 @@ category('Table view', () => {
136
136
  expect(filteredMonomers.length, 0, `Filter is not empty for position ${position} after initialization`);
137
137
 
138
138
  // Select by second monomer-position pair
139
- model.modifyMonomerPositionSelection(secondPair.monomer, secondPair.position, true);
140
- expect(model.invariantMapSelection[secondPair.position].includes(secondPair.monomer), true,
141
- `Monomer ${secondPair.monomer} is not filtered at position ${secondPair.position}`);
139
+ model.modifyInvariantMapSelection(secondPair);
140
+ expect(model.invariantMapSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), true,
141
+ `Monomer ${secondPair.monomerOrCluster} is not filtered at position ${secondPair.positionOrClusterType}`);
142
142
  expect(selection.trueCount, secondPair.imCount, `Filter count is not equal to ${secondPair.imCount} ` +
143
- `for monomer ${secondPair.monomer} at position ${secondPair.position}`);
143
+ `for monomer ${secondPair.monomerOrCluster} at position ${secondPair.positionOrClusterType}`);
144
144
 
145
145
  // Select by first monomer-position pair
146
- model.modifyMonomerPositionSelection(firstPair.monomer, firstPair.position, true);
147
- expect(model.invariantMapSelection[firstPair.position].includes(firstPair.monomer), true,
148
- `Monomer ${firstPair.monomer} is not filtered at position ${firstPair.position}`);
146
+ model.modifyInvariantMapSelection(firstPair, {shiftPressed: true, ctrlPressed: false});
147
+ expect(model.invariantMapSelection[firstPair.positionOrClusterType].includes(firstPair.monomerOrCluster), true,
148
+ `Monomer ${firstPair.monomerOrCluster} is not filtered at position ${firstPair.positionOrClusterType}`);
149
149
  expect(selection.trueCount, secondPair.imCount, `Filter count is not equal to ${secondPair.imCount} ` +
150
- `for monomer ${firstPair.monomer} at position ${firstPair.position}`);
150
+ `for monomer ${firstPair.monomerOrCluster} at position ${firstPair.positionOrClusterType}`);
151
151
 
152
152
  // Deselect filter for second monomer-position pair
153
- model.modifyMonomerPositionSelection(secondPair.monomer, secondPair.position, true);
154
- expect(model.invariantMapSelection[secondPair.position].includes(secondPair.monomer), false,
155
- `Monomer ${secondPair.monomer} is still filtered at position ${secondPair.position} after ` +
153
+ model.modifyInvariantMapSelection(secondPair, {shiftPressed: true, ctrlPressed: true});
154
+ expect(model.invariantMapSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), false,
155
+ `Monomer ${secondPair.monomerOrCluster} is still filtered at position ${secondPair.positionOrClusterType} after ` +
156
156
  `deselection`);
157
157
  expect(selection.trueCount, firstPair.imCount, `Filter count is not equal to ${firstPair.imCount} ` +
158
- `for monomer ${firstPair.monomer} at position ${firstPair.position} after deselection of ` +
159
- `monomer ${secondPair.monomer} at position ${secondPair.position}`);
158
+ `for monomer ${firstPair.monomerOrCluster} at position ${firstPair.positionOrClusterType} after deselection of ` +
159
+ `monomer ${secondPair.monomerOrCluster} at position ${secondPair.positionOrClusterType}`);
160
160
 
161
161
  // Clear selection
162
- model.initInvariantMapSelection({cleanInit: true});
162
+ model.initInvariantMapSelection();
163
163
  expect(selection.trueCount, 0, `Filter count is not equal to ${0} after clearing monomer-position filter`);
164
164
 
165
165
  for (const [position, filteredMonomers] of Object.entries(model.invariantMapSelection)) {
@@ -3,12 +3,12 @@ import * as DG from 'datagrok-api/dg';
3
3
 
4
4
  import {awaitCheck, before, category, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
5
5
  import {aligned1} from './test-data';
6
- import {PeptidesModel, VIEWER_TYPE} from '../model';
6
+ import {CLUSTER_TYPE, PeptidesModel, VIEWER_TYPE} from '../model';
7
7
  import {_package} from '../package-test';
8
8
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
9
  import {scaleActivity} from '../utils/misc';
10
10
  import {startAnalysis} from '../widgets/peptides';
11
- import {MONOMER_POSITION_MODE, MonomerPosition, MostPotentResidues, showTooltip} from '../viewers/sar-viewer';
11
+ import {SELECTION_MODE, MonomerPosition, MostPotentResidues} from '../viewers/sar-viewer';
12
12
  import {SCALING_METHODS} from '../utils/constants';
13
13
  import {LST_PROPERTIES, LogoSummaryTable} from '../viewers/logo-summary';
14
14
  import {PositionHeight} from '@datagrok-libraries/bio/src/viewers/web-logo';
@@ -63,7 +63,8 @@ category('Viewers: Monomer-Position', () => {
63
63
  test('Tooltip', async () => {
64
64
  const cellCoordinates = {col: '9', row: 6};
65
65
  const gc = mpViewer.viewerGrid.cell(cellCoordinates.col, cellCoordinates.row);
66
- expect(showTooltip(gc, 0, 0, model), true,
66
+ const mp = mpViewer.getMonomerPosition(gc);
67
+ expect(model.showTooltip(mp, 0, 0), true,
67
68
  `Tooltip is not shown for grid cell at column '${cellCoordinates.col}', row ${cellCoordinates.row}`);
68
69
  });
69
70
 
@@ -71,16 +72,16 @@ category('Viewers: Monomer-Position', () => {
71
72
  if (mpViewer === null)
72
73
  throw new Error('Monomer-Position viewer doesn\'t exist');
73
74
 
74
- expect(mpViewer.mode, MONOMER_POSITION_MODE.MUTATION_CLIFFS,
75
- `Default Monomer-Position mode is not ${MONOMER_POSITION_MODE.MUTATION_CLIFFS}`);
75
+ expect(mpViewer.mode, SELECTION_MODE.MUTATION_CLIFFS,
76
+ `Default Monomer-Position mode is not ${SELECTION_MODE.MUTATION_CLIFFS}`);
76
77
 
77
- mpViewer.mode = MONOMER_POSITION_MODE.INVARIANT_MAP;
78
- expect(mpViewer.mode, MONOMER_POSITION_MODE.INVARIANT_MAP,
79
- `Monomer-Position mode is not ${MONOMER_POSITION_MODE.INVARIANT_MAP} after switching`);
78
+ mpViewer.mode = SELECTION_MODE.INVARIANT_MAP;
79
+ expect(mpViewer.mode, SELECTION_MODE.INVARIANT_MAP,
80
+ `Monomer-Position mode is not ${SELECTION_MODE.INVARIANT_MAP} after switching`);
80
81
 
81
- mpViewer.mode = MONOMER_POSITION_MODE.MUTATION_CLIFFS;
82
- expect(mpViewer.mode, MONOMER_POSITION_MODE.MUTATION_CLIFFS,
83
- `Monomer-Position mode is not ${MONOMER_POSITION_MODE.MUTATION_CLIFFS} after switching`);
82
+ mpViewer.mode = SELECTION_MODE.MUTATION_CLIFFS;
83
+ expect(mpViewer.mode, SELECTION_MODE.MUTATION_CLIFFS,
84
+ `Monomer-Position mode is not ${SELECTION_MODE.MUTATION_CLIFFS} after switching`);
84
85
  });
85
86
  }, {clear: false});
86
87
 
@@ -123,7 +124,8 @@ category('Viewers: Most Potent Residues', () => {
123
124
  test('Tooltip', async () => {
124
125
  const cellCoordinates = {col: 'Diff', row: 6};
125
126
  const gc = mprViewer.viewerGrid.cell(cellCoordinates.col, cellCoordinates.row);
126
- expect(showTooltip(gc, 0, 0, model), true,
127
+ const mp = mprViewer.getMonomerPosition(gc);
128
+ expect(model.showTooltip(mp, 0, 0), true,
127
129
  `Tooltip is not shown for grid cell at column '${cellCoordinates.col}', row ${cellCoordinates.row}`);
128
130
  });
129
131
  });
@@ -183,7 +185,7 @@ category('Viewers: Logo Summary Table', () => {
183
185
 
184
186
  test('Tooltip', async () => {
185
187
  const cluster = '0';
186
- const tooltipElement = lstViewer.showTooltip(cluster, 0, 0);
188
+ const tooltipElement = lstViewer.showTooltip({monomerOrCluster: cluster, positionOrClusterType: CLUSTER_TYPE.ORIGINAL}, 0, 0);
187
189
  expect(tooltipElement !== null, true, `Tooltip is not shown for cluster '${cluster}'`);
188
190
  });
189
191
  }, {clear: false});
@@ -3,7 +3,7 @@ import * as DG from 'datagrok-api/dg';
3
3
 
4
4
  import {category, test, before, expect, awaitCheck} from '@datagrok-libraries/utils/src/test';
5
5
  import {_package} from '../package-test';
6
- import {PeptidesModel, VIEWER_TYPE} from '../model';
6
+ import {CLUSTER_TYPE, PeptidesModel, VIEWER_TYPE} from '../model';
7
7
  import {scaleActivity} from '../utils/misc';
8
8
  import {startAnalysis} from '../widgets/peptides';
9
9
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
@@ -221,13 +221,12 @@ category('Widgets: Actions', () => {
221
221
  const customClusterList = wu(model.customClusters).toArray();
222
222
  expect(customClusterList.length, 1, 'Expected to have 1 custom cluster');
223
223
  const clustName = customClusterList[0].name;
224
- expect(model.df.col(clustName) !== null, true,
225
- 'Expected to have custom cluster column in the table');
224
+ expect(model.df.col(clustName) !== null, true, 'Expected to have custom cluster column in the table');
226
225
  expect(lstViewer.viewerGrid.table.getCol(C.LST_COLUMN_NAMES.CLUSTER).categories.indexOf(clustName) !== -1, true,
227
226
  'Expected to have custom cluster in the Logo Summary Table');
228
227
 
229
228
  // Remove custom cluster
230
- model.modifyClusterSelection(clustName);
229
+ model.modifyClusterSelection({monomerOrCluster: clustName, positionOrClusterType: CLUSTER_TYPE.CUSTOM});
231
230
  lstViewer.removeCluster();
232
231
  expect(wu(model.customClusters).toArray().length, 0, 'Expected to have 0 custom clusters after removing one');
233
232
  expect(model.df.col(clustName) === null, true,
@@ -2,7 +2,7 @@ import * as DG from 'datagrok-api/dg';
2
2
 
3
3
  import * as C from './constants';
4
4
  import * as types from './types';
5
- import {PositionStats, MonomerPositionStats} from '../model';
5
+ import {PositionStats, MonomerPositionStats, CLUSTER_TYPE} from '../model';
6
6
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
7
7
  import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
8
 
@@ -13,40 +13,34 @@ export function renderCellSelection(canvasContext: CanvasRenderingContext2D, bou
13
13
  }
14
14
 
15
15
  /** A function that sets amino acid residue cell renderer to the specified column */
16
- export function setAARRenderer(col: DG.Column, alphabet: string): void {
16
+ export function setMonomerRenderer(col: DG.Column, alphabet: string): void {
17
17
  col.semType = C.SEM_TYPES.MONOMER;
18
18
  col.setTag('cell.renderer', C.SEM_TYPES.MONOMER);
19
19
  col.tags[C.TAGS.ALPHABET] = alphabet;
20
20
  }
21
21
 
22
- export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
22
+ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentMonomer: string,
23
23
  currentPosition: string, monomerPositionStats: MonomerPositionStats, bound: DG.Rect,
24
- mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.MutationCliffs | null = null,
25
- twoColorMode: boolean = false, renderNums: boolean = true): void {
24
+ mutationCliffsSelection: types.Selection, substitutionsInfo: types.MutationCliffs | null = null,
25
+ _twoColorMode: boolean = false, renderNums: boolean = true): void {
26
26
  const positionStats = monomerPositionStats[currentPosition];
27
- const pVal: number = positionStats[currentAAR].pValue;
28
- const currentMeanDiff = positionStats[currentAAR].meanDifference;
29
-
30
- let coef: string;
31
- const isMeanDeltaNegative = currentMeanDiff < 0;
32
- if (pVal < 0.01)
33
- coef = isMeanDeltaNegative && twoColorMode ? '#FF7900' : '#299617';
34
- else if (pVal < 0.05)
35
- coef = isMeanDeltaNegative && twoColorMode ? '#FFA500' : '#32CD32';
36
- else if (pVal < 0.1)
37
- coef = isMeanDeltaNegative && twoColorMode ? '#FBCEB1' : '#98FF98';
38
- else
39
- coef = DG.Color.toHtml(DG.Color.lightLightGray);
40
-
41
-
42
- const minMeanDifference = twoColorMode ? 0 : monomerPositionStats.general.minMeanDifference;
43
- const maxMeanDifference = twoColorMode ?
44
- Math.max(Math.abs(monomerPositionStats.general.minMeanDifference), monomerPositionStats.general.maxMeanDifference) :
45
- monomerPositionStats.general.maxMeanDifference;
46
- const currentMeanDifference = twoColorMode ? Math.abs(currentMeanDiff) : currentMeanDiff;
47
-
48
- const rCoef = (currentMeanDifference - minMeanDifference) / (maxMeanDifference - minMeanDifference);
49
-
27
+ const pVal = positionStats![currentMonomer]!.pValue;
28
+ const currentMeanDifference = positionStats![currentMonomer]!.meanDifference;
29
+
30
+ // Transform p-value to increase intensity for smaller values and decrease for larger values
31
+ const maxPValComplement = 1 - positionStats!.general.maxPValue;
32
+ const minPValComplement = 1 - positionStats!.general.minPValue;
33
+ const pValCentering = Math.min(maxPValComplement, minPValComplement);
34
+ const centeredMaxPValComplement = maxPValComplement - pValCentering;
35
+ const centeredMinPValComplement = minPValComplement - pValCentering;
36
+ const centeredPValLimit = Math.max(centeredMaxPValComplement, centeredMinPValComplement);
37
+ const pValComplement = pVal === null ? 0 : 1 - pVal - pValCentering;
38
+
39
+ const coef = DG.Color.toHtml(pVal === null ? DG.Color.lightLightGray :
40
+ DG.Color.scaleColor(currentMeanDifference >= 0 ? pValComplement : -pValComplement, -centeredPValLimit, centeredPValLimit));
41
+
42
+ const maxMeanDifference = Math.max(Math.abs(monomerPositionStats.general.minMeanDifference), monomerPositionStats.general.maxMeanDifference);
43
+ const rCoef = Math.abs(currentMeanDifference) / maxMeanDifference;
50
44
  const maxRadius = 0.9 * (bound.width > bound.height ? bound.height : bound.width) / 2;
51
45
  const radius = Math.floor(maxRadius * rCoef);
52
46
 
@@ -54,12 +48,12 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
54
48
  const midY = bound.y + bound.height / 2;
55
49
  canvasContext.beginPath();
56
50
  canvasContext.fillStyle = coef;
57
- canvasContext.arc(midX, midY, radius < 3 ? 3 : radius, 0, Math.PI * 2, true);
51
+ canvasContext.arc(midX, midY, radius < 3 || pVal === null ? 3 : radius, 0, Math.PI * 2, true);
58
52
  canvasContext.closePath();
59
53
  canvasContext.fill();
60
54
 
61
55
  if (renderNums) {
62
- const substitutions = substitutionsInfo?.get(currentAAR)?.get(currentPosition)?.entries() ?? null;
56
+ const substitutions = substitutionsInfo?.get(currentMonomer)?.get(currentPosition)?.entries() ?? null;
63
57
  if (substitutions !== null) {
64
58
  canvasContext.textBaseline = 'middle';
65
59
  canvasContext.textAlign = 'center';
@@ -79,13 +73,13 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
79
73
  }
80
74
  }
81
75
 
82
- const aarSelection = mutationCliffsSelection[currentPosition];
83
- if (aarSelection && aarSelection.includes(currentAAR))
76
+ const monomerSelection = mutationCliffsSelection[currentPosition];
77
+ if (monomerSelection && monomerSelection.includes(currentMonomer))
84
78
  renderCellSelection(canvasContext, bound);
85
79
  }
86
80
 
87
- export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
88
- currentPosition: string, invariantMapSelection: types.PositionToAARList, cellValue: number, bound: DG.Rect,
81
+ export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D, currentMonomer: string,
82
+ currentPosition: string, invariantMapSelection: types.Selection, cellValue: number, bound: DG.Rect,
89
83
  color: number): void {
90
84
  canvasContext.fillStyle = DG.Color.toHtml(color);
91
85
  canvasContext.fillRect(bound.x, bound.y, bound.width, bound.height);
@@ -95,20 +89,20 @@ export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D,
95
89
  canvasContext.fillStyle = '#000';
96
90
  canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
97
91
 
98
- const aarSelection = invariantMapSelection[currentPosition];
99
- if (aarSelection && aarSelection.includes(currentAAR))
92
+ const monomerSelection = invariantMapSelection[currentPosition];
93
+ if (monomerSelection && monomerSelection.includes(currentMonomer))
100
94
  renderCellSelection(canvasContext, bound);
101
95
  }
102
96
 
103
97
  export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, cellValue: string,
104
- clusterSelection: string[], bound: DG.Rect): void {
98
+ clusterSelection: types.Selection, bound: DG.Rect): void {
105
99
  canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
106
100
  canvasContext.textAlign = 'center';
107
101
  canvasContext.textBaseline = 'middle';
108
102
  canvasContext.fillStyle = '#000';
109
103
  canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
110
104
 
111
- if (clusterSelection.includes(cellValue))
105
+ if (clusterSelection[CLUSTER_TYPE.CUSTOM].includes(cellValue) || clusterSelection[CLUSTER_TYPE.ORIGINAL].includes(cellValue))
112
106
  renderCellSelection(canvasContext, bound);
113
107
  }
114
108
 
@@ -136,7 +130,7 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
136
130
 
137
131
  const monomerBounds: { [monomer: string]: DG.Rect } = {};
138
132
  for (const monomer of sortedOrder) {
139
- const monomerHeight = barHeight * (stats[monomer].count / rowCount);
133
+ const monomerHeight = barHeight * (stats[monomer]!.count / rowCount);
140
134
  const selectionHeight = barHeight * ((monomerSelectionStats[monomer] ?? 0) / rowCount);
141
135
  const currentBound = new DG.Rect(xStart / pr, currentY / pr, barWidth / pr, monomerHeight / pr);
142
136
  monomerBounds[monomer] = currentBound;
@@ -29,6 +29,7 @@ export enum TAGS {
29
29
  POSITION = 'pos',
30
30
  SEPARATOR = 'separator',
31
31
  SELECTION = 'selection',
32
+ MUTATION_CLIFFS_SELECTION = 'mutationCliffsSelection',
32
33
  ALPHABET = 'alphabet',
33
34
  FILTER = 'filter',
34
35
  INVARIANT_MAP_SELECTION = 'invariantMapSelection',
package/src/utils/misc.ts CHANGED
@@ -1,11 +1,8 @@
1
- import * as grok from 'datagrok-api/grok';
2
1
  import * as ui from 'datagrok-api/ui';
3
2
  import * as DG from 'datagrok-api/dg';
4
3
  import * as C from './constants';
5
4
  import * as type from './types';
6
5
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
7
- import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
8
- import {TAGS as bioTags} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
6
 
10
7
  export function getTypedArrayConstructor(
11
8
  maxNum: number): Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor {
@@ -44,9 +41,9 @@ export function scaleActivity(activityCol: DG.Column<number>, scaling: C.SCALING
44
41
  }
45
42
 
46
43
  //TODO: optimize
47
- export function calculateSelected(df: DG.DataFrame): type.MonomerSelectionStats {
44
+ export function calculateSelected(df: DG.DataFrame): type.SelectionStats {
48
45
  const monomerColumns: DG.Column<string>[] = df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
49
- const selectedObj: type.MonomerSelectionStats = {};
46
+ const selectedObj: type.SelectionStats = {};
50
47
  for (const idx of df.selection.getSelectedIndexes()) {
51
48
  for (const col of monomerColumns) {
52
49
  const monomer = col.get(idx);
@@ -5,12 +5,18 @@ import BitArray from '@datagrok-libraries/utils/src/bit-array';
5
5
 
6
6
  export type Stats = {
7
7
  count: number,
8
- pValue: number,
8
+ pValue: number | null,
9
9
  meanDifference: number,
10
10
  ratio: number,
11
+ mask: BitArray,
11
12
  };
12
13
 
13
14
  export function getStats(data: RawData | number[], bitArray: BitArray): Stats {
15
+ if (data.length !== bitArray.length && data.some((v, i) => i >= bitArray.length ? v !== 0 : false))
16
+ throw new Error('PeptidesError: Data and bit array have different lengths');
17
+ if (bitArray.falseCount() === 0 || bitArray.trueCount() === 0)
18
+ throw new Error('PeptidesError: One of the samples is empty');
19
+
14
20
  const selected = new Float32Array(bitArray.trueCount());
15
21
  const rest = new Float32Array(bitArray.falseCount());
16
22
 
@@ -23,13 +29,26 @@ export function getStats(data: RawData | number[], bitArray: BitArray): Stats {
23
29
  rest[restIndex++] = data[i];
24
30
  }
25
31
 
32
+ if (selected.length === 1 || rest.length === 1) {
33
+ const selectedMean = selected.reduce((a, b) => a + b, 0) / selected.length;
34
+ const restMean = rest.reduce((a, b) => a + b, 0) / rest.length;
35
+ return {
36
+ count: selected.length,
37
+ pValue: null,
38
+ meanDifference: selectedMean - restMean,
39
+ ratio: selected.length / (bitArray.length),
40
+ mask: bitArray,
41
+ };
42
+ }
43
+
26
44
  const testResult = tTest(selected, rest);
27
45
  const currentMeanDiff = testResult['Mean difference']!;
28
46
  return {
29
47
  count: selected.length,
30
- pValue: testResult[currentMeanDiff >= 0 ? 'p-value more' : 'p-value less'] || 0,
31
- meanDifference: currentMeanDiff || 0,
48
+ pValue: testResult[currentMeanDiff >= 0 ? 'p-value more' : 'p-value less'],
49
+ meanDifference: currentMeanDiff,
32
50
  ratio: selected.length / (bitArray.length),
51
+ mask: bitArray,
33
52
  };
34
53
  }
35
54
 
@@ -1,15 +1,16 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import {SCALING_METHODS} from './constants';
3
+ import {ClusterType} from '../model';
3
4
 
4
5
  export type DataFrameDict = {[key: string]: DG.DataFrame};
5
6
 
6
7
  export type RawData = Int32Array | Uint32Array | Float32Array | Float64Array;
7
8
  export type UTypedArray = Uint8Array | Uint16Array | Uint32Array;
8
- //AAR: (Position: (index: indexList))
9
+ //Monomer: (Position: (index: indexList))
9
10
  export type MutationCliffs = Map<string, Map<string, Map<number, number[] | UTypedArray>>>;
10
- export type PositionToAARList = {[postiton: string]: string[]};
11
-
12
- export type MonomerSelectionStats = {[position: string]: {[monomer: string]: number}};
11
+ export type Selection = {[positionOrClusterType: string | ClusterType]: string[]};
12
+ export type SelectionItem = {positionOrClusterType: string | ClusterType, monomerOrCluster: string};
13
+ export type SelectionStats = {[positionOrClusterType: string | ClusterType]: { [monomerOrCluster: string]: number}};
13
14
 
14
15
  export type PeptidesSettings = {
15
16
  sequenceColumnName?: string,
@@ -48,4 +49,4 @@ export type StatsInfo = {
48
49
 
49
50
  export type RawColumn = {name: string, rawData: RawData, cat?: string[]};
50
51
 
51
- export type CustomClusters = {[clusterName: string]: number[] | Int32Array};
52
+ export type SelectionOptions = {shiftPressed: boolean, ctrlPressed: boolean};