@datagrok/peptides 1.14.0 → 1.15.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.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @license
3
+ *
4
+ * Copyright 2019 Google LLC. All Rights Reserved.
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ * ==============================================================================
18
+ */
19
+
20
+ /**
21
+ * @license
22
+ * BSD 3-Clause License
23
+ *
24
+ * Copyright (c) 2017, Leland McInnes
25
+ * All rights reserved.
26
+ *
27
+ * Redistribution and use in source and binary forms, with or without
28
+ * modification, are permitted provided that the following conditions are met:
29
+ *
30
+ * * Redistributions of source code must retain the above copyright notice, this
31
+ * list of conditions and the following disclaimer.
32
+ *
33
+ * * Redistributions in binary form must reproduce the above copyright notice,
34
+ * this list of conditions and the following disclaimer in the documentation
35
+ * and/or other materials provided with the distribution.
36
+ *
37
+ * * Neither the name of the copyright holder nor the names of its
38
+ * contributors may be used to endorse or promote products derived from
39
+ * this software without specific prior written permission.
40
+ *
41
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
42
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
45
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
48
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51
+ */
@@ -0,0 +1,23 @@
1
+ # Logo Summary Table
2
+
3
+ Logo Summary Table shows WebLogo, activity distribution and statistics for each of the clusters in data. Statistics include
4
+ mean difference, p-value, count and ratio.
5
+
6
+ # Responsiveness
7
+
8
+ Logo Summary Table reacts to filters applied to the data and shows only clusters of filtered rows. In this case WebLogo,
9
+ activity distribution and statistics are calculated with respect to filtered rows.
10
+
11
+ ## Interactivity
12
+
13
+ Logo Summary Tabl viewer selection follows default pattern as any other Datagrok viewer.
14
+
15
+ | | |
16
+ |------------------|-------------------------------|
17
+ | Click | Single selection of Cluster |
18
+ | Ctrl+Click | Toggle Cluster selection state|
19
+ | Shift+Click | Add Cluster to selection |
20
+ | Ctrl+Shift+Click | Deselect Cluster |
21
+
22
+ Hovering over any cell will show tooltip with distribution and statistics of the monomer-position and highlight corresponding
23
+ points on other viewers.
@@ -0,0 +1,31 @@
1
+ # Monomer-Position viewer
2
+
3
+ Monomer-Position viewer is a matrix-like grid, where rows correspond to monomers and columns to positions. This viewer works in two modes: Mutation Cliffs and Invariant Map.
4
+
5
+ ## Mutation Cliffs mode
6
+
7
+ Mutation Cliffs mode highlights the most signficant monomer-position pairs. The significance of the monomer-position is
8
+ color-coded with blue for negative mean difference of the sequences containing monomer-position vs. rest of the sequences,
9
+ and red for positive mean difference. Color intensity is defined by p-value. The size of the circle represents the value of mean difference:
10
+ smaller circles represent low mean difference values; large circles represent hight mean difference values. Some of the
11
+ cells contain number of unique sequences for given monomer-position, that form Mutation Cliff pairs.
12
+
13
+ ## Invariant Map mode
14
+
15
+ Invariant Map mode shows number of sequences that contain monomer-position. Cells are color-coded based on the aggregation
16
+ function on some numeric column. By default average scaled activity values for given monomer-position is used. Column and
17
+ aggregation function can be changed in viewer properties.
18
+
19
+ ## Interactivity
20
+
21
+ Monomer-Position viewer selection follows default pattern as any other Datagrok viewer.
22
+
23
+ | | |
24
+ |------------------|----------------------------------------|
25
+ | Click | Single selection of Monomer-Position |
26
+ | Ctrl+Click | Toggle Monomer-Position selection state|
27
+ | Shift+Click | Add Monomer-Position to selection |
28
+ | Ctrl+Shift+Click | Deselect Monomer-Position |
29
+
30
+ Hovering over any cell will show tooltip with distribution and statistics of the monomer-position and highlight corresponding
31
+ points on other viewers.
@@ -0,0 +1,17 @@
1
+ # Most Potent Residues
2
+
3
+ Most Potent Residues viewer for each position finds the most potent monomer and shows statistics for the monomer-position. Statistics include mean difference, p-value, count and ratio.
4
+
5
+ ## Interactivity
6
+
7
+ Most Potent Residues viewer selection follows default pattern as any other Datagrok viewer.
8
+
9
+ | | |
10
+ |------------------|----------------------------------------|
11
+ | Click | Single selection of Monomer-Position |
12
+ | Ctrl+Click | Toggle Monomer-Position selection state|
13
+ | Shift+Click | Add Monomer-Position to selection |
14
+ | Ctrl+Shift+Click | Deselect Monomer-Position |
15
+
16
+ Hovering over any cell will show tooltip with distribution and statistics of the monomer-position and highlight corresponding
17
+ points on other viewers.
@@ -0,0 +1,8 @@
1
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M20.6603 18.7754C20.9386 18.7754 21.1871 18.697 21.4058 18.5401C21.6244 18.3832 21.7984 18.1622 21.9276 17.877C22.0618 17.5918 22.1338 17.2602 22.1438 16.8824H24C23.9901 17.6667 23.836 18.369 23.5378 18.9893C23.2396 19.6096 22.842 20.1016 22.345 20.4652C21.853 20.8217 21.3014 21 20.6901 21C20.0689 21 19.5272 20.8503 19.065 20.5508C18.6028 20.2513 18.2176 19.8342 17.9095 19.2995C17.6063 18.7647 17.3777 18.1444 17.2236 17.4385C17.0745 16.7326 17 15.9768 17 15.1711V14.8289C17 14.0232 17.0745 13.2674 17.2236 12.5615C17.3777 11.8556 17.6063 11.2353 17.9095 10.7005C18.2176 10.1658 18.6028 9.74866 19.065 9.4492C19.5272 9.14973 20.0664 9 20.6826 9C21.3337 9 21.9052 9.18182 22.3972 9.54545C22.8942 9.90909 23.2819 10.4225 23.5602 11.0856C23.8435 11.7487 23.9901 12.5294 24 13.4278H22.1438C22.1338 13.0143 22.0692 12.6435 21.9499 12.3155C21.8307 11.9875 21.6617 11.7237 21.443 11.5241C21.2244 11.3244 20.9585 11.2246 20.6454 11.2246C20.3124 11.2246 20.0341 11.3244 19.8104 11.5241C19.5918 11.7237 19.4203 11.9982 19.2961 12.3476C19.1768 12.6898 19.0923 13.0749 19.0426 13.5027C18.9979 13.9234 18.9755 14.3654 18.9755 14.8289V15.1711C18.9755 15.6417 18.9979 16.0909 19.0426 16.5187C19.0923 16.9465 19.1768 17.3316 19.2961 17.6738C19.4203 18.0089 19.5918 18.2763 19.8104 18.4759C20.0341 18.6756 20.3174 18.7754 20.6603 18.7754Z" fill="#40607F"/>
3
+ <path d="M9.87361 5.73214L5.24535 21H2L8.06691 3H10.1413L9.87361 5.73214ZM13.7435 21L9.09294 5.73214L8.81413 3H10.8996L17 21H13.7435ZM13.5316 14.3118V16.9945H4.82156V14.3118H13.5316Z" fill="#40607F"/>
4
+ <path d="M34 7V21H31.8769L27.1154 11.2885V21H25V7H27.1154L31.8923 16.7212V7H34Z" fill="#40607F" fill-opacity="0.5"/>
5
+ <path d="M6.44251 31.0838L8.63182 23H9.81707L9.89257 24.7033L7.55226 33H6.29907L6.44251 31.0838ZM5.06098 23L6.85772 31.0563V33H5.49129L3 23H5.06098ZM12.1649 31.022L13.9315 23H16L13.5087 33H12.1423L12.1649 31.022ZM10.3833 23L12.5726 31.1113L12.7009 33H11.4477L9.11498 24.6964L9.20557 23H10.3833Z" fill="#40607F" fill-opacity="0.5"/>
6
+ <path d="M21.3392 31.554V24H23V32.8843H21.5016L21.3392 31.554ZM17 29.8303V29.7089C17 29.2307 17.0583 28.7969 17.1748 28.4075C17.2955 28.0141 17.4703 27.6767 17.6993 27.3952C17.9282 27.1138 18.205 26.8959 18.5297 26.7416C18.8585 26.5874 19.231 26.5103 19.6472 26.5103C20.051 26.5103 20.4027 26.5855 20.7024 26.7359C21.0062 26.8862 21.2643 27.1003 21.4766 27.3779C21.693 27.6555 21.8658 27.9852 21.9948 28.367C22.1238 28.7449 22.2175 29.1613 22.2758 29.6163V29.946C22.2175 30.3895 22.1238 30.7963 21.9948 31.1665C21.8658 31.5366 21.693 31.8605 21.4766 32.1382C21.2643 32.412 21.0062 32.624 20.7024 32.7744C20.3985 32.9248 20.0427 33 19.6348 33C19.2227 33 18.8522 32.921 18.5234 32.7629C18.1988 32.6048 17.922 32.383 17.693 32.0977C17.4683 31.8123 17.2955 31.4769 17.1748 31.0913C17.0583 30.7057 17 30.2853 17 29.8303ZM18.6545 29.7089V29.8303C18.6545 30.1003 18.6795 30.3528 18.7294 30.588C18.7794 30.8233 18.8606 31.0315 18.9729 31.2127C19.0853 31.3901 19.2289 31.5289 19.4037 31.6292C19.5827 31.7294 19.7992 31.7796 20.0531 31.7796C20.3777 31.7796 20.6441 31.714 20.8522 31.5829C21.0645 31.4479 21.2289 31.2648 21.3455 31.0334C21.462 30.7982 21.5369 30.5341 21.5702 30.241V29.3329C21.5536 29.1015 21.5099 28.8875 21.4391 28.6909C21.3725 28.4942 21.2768 28.3246 21.1519 28.1819C21.0312 28.0392 20.8814 27.9274 20.7024 27.8464C20.5234 27.7654 20.3111 27.7249 20.0656 27.7249C19.8117 27.7249 19.5952 27.777 19.4162 27.8811C19.2373 27.9814 19.0916 28.1221 18.9792 28.3033C18.8668 28.4846 18.7836 28.6947 18.7294 28.9338C18.6795 29.1729 18.6545 29.4312 18.6545 29.7089Z" fill="#40607F" fill-opacity="0.7"/>
7
+ <path d="M28.9545 33H26.1L26.1182 31.3681H28.9545C29.7242 31.3681 30.3697 31.2271 30.8909 30.9451C31.4121 30.658 31.8061 30.2475 32.0727 29.7136C32.3394 29.1747 32.4727 28.53 32.4727 27.7795V27.2129C32.4727 26.6337 32.397 26.1225 32.2455 25.6793C32.0939 25.236 31.8697 24.8633 31.5727 24.5611C31.2818 24.2589 30.9212 24.0298 30.4909 23.8736C30.0606 23.7175 29.5667 23.6394 29.0091 23.6394H26.0455V22H29.0091C29.8939 22 30.7 22.1234 31.4273 22.3702C32.1606 22.617 32.7939 22.9721 33.3273 23.4354C33.8667 23.8938 34.2788 24.4428 34.5636 25.0824C34.8545 25.7221 35 26.4373 35 27.228V27.7795C35 28.5652 34.8545 29.2804 34.5636 29.9251C34.2788 30.5648 33.8667 31.1138 33.3273 31.5721C32.7939 32.0304 32.1576 32.383 31.4182 32.6298C30.6788 32.8766 29.8576 33 28.9545 33ZM27.5 22V33H25V22H27.5Z" fill="#40607F"/>
8
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M30 7.5C30 6.94772 29.5523 6.5 29 6.5H15C14.4477 6.5 14 6.94772 14 7.5V7.5C14 8.05228 14.4477 8.5 15 8.5H29C29.5523 8.5 30 8.05228 30 7.5V7.5Z" fill="#B3BFCC"/>
3
+ <path d="M30 14.5C30 13.9477 29.5523 13.5 29 13.5H15C14.4477 13.5 14 13.9477 14 14.5V14.5C14 15.0523 14.4477 15.5 15 15.5H29C29.5523 15.5 30 15.0523 30 14.5V14.5Z" fill="#B3BFCC"/>
4
+ <path d="M30 21.5C30 20.9477 29.5523 20.5 29 20.5H15C14.4477 20.5 14 20.9477 14 21.5V21.5C14 22.0523 14.4477 22.5 15 22.5H29C29.5523 22.5 30 22.0523 30 21.5V21.5Z" fill="#B3BFCC"/>
5
+ <path d="M30 28.5C30 27.9477 29.5523 27.5 29 27.5H15C14.4477 27.5 14 27.9477 14 28.5V28.5C14 29.0523 14.4477 29.5 15 29.5H29C29.5523 29.5 30 29.0523 30 28.5V28.5Z" fill="#B3BFCC"/>
6
+ <circle cx="8" cy="7.5" r="3" fill="#40607F"/>
7
+ <circle cx="8" cy="14.5" r="1.5" fill="#7990A5"/>
8
+ <circle cx="8" cy="28.5" r="2" fill="#7990A5"/>
9
+ <circle cx="8" cy="21.5" r="2" fill="#40607F"/>
10
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="9" cy="9.5" r="3" fill="#40607F"/>
3
+ <circle cx="18" cy="9.5" r="2" fill="#7990A5"/>
4
+ <circle cx="9" cy="18" r="2" fill="#7990A5"/>
5
+ <circle cx="9" cy="27" r="2" fill="#7990A5"/>
6
+ <circle cx="18" cy="18" r="1.5" fill="#7990A5"/>
7
+ <circle cx="28" cy="18" r="2" fill="#7990A5"/>
8
+ <circle cx="28" cy="27" r="1.5" fill="#7990A5"/>
9
+ <circle cx="28" cy="9.5" r="3" fill="#40607F"/>
10
+ <circle cx="18" cy="27" r="3" fill="#40607F"/>
11
+ </svg>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
3
  "friendlyName": "Peptides",
4
- "version": "1.14.0",
4
+ "version": "1.15.0",
5
5
  "author": {
6
6
  "name": "Volodymyr Dyma",
7
7
  "email": "vdyma@datagrok.ai"
@@ -13,10 +13,10 @@
13
13
  "directory": "packages/Peptides"
14
14
  },
15
15
  "dependencies": {
16
- "@datagrok-libraries/bio": "^5.38.2",
17
- "@datagrok-libraries/ml": "^6.3.40",
16
+ "@datagrok-libraries/bio": "^5.38.11",
17
+ "@datagrok-libraries/ml": "^6.3.48",
18
18
  "@datagrok-libraries/statistics": "^1.2.7",
19
- "@datagrok-libraries/utils": "^4.1.13",
19
+ "@datagrok-libraries/utils": "^4.1.15",
20
20
  "@datagrok-libraries/tutorials": "^1.3.7",
21
21
  "cash-dom": "^8.1.5",
22
22
  "datagrok-api": "^1.16.4",
package/src/model.ts CHANGED
@@ -33,6 +33,10 @@ import {findMutations} from './utils/algorithms';
33
33
  import {createDistanceMatrixWorker} from './utils/worker-creator';
34
34
  import {getSelectionWidget} from './widgets/selection';
35
35
 
36
+ import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule-distance-functions';
37
+ import {BitArrayMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
38
+ import {DimReductionMethods, ITSNEOptions, IUMAPOptions} from '@datagrok-libraries/ml/src/reduce-dimensionality';
39
+
36
40
  export type SummaryStats = {
37
41
  minCount: number, maxCount: number,
38
42
  minMeanDifference: number, maxMeanDifference: number,
@@ -88,6 +92,7 @@ export class PeptidesModel {
88
92
  subs: rxjs.Subscription[] = [];
89
93
  isHighlighting: boolean = false;
90
94
  latestSelectionItem: (type.SelectionItem & {kind: SELECTION_MODE | 'Cluster'}) | null = null;
95
+ controlFire: boolean = false;
91
96
 
92
97
  private constructor(dataFrame: DG.DataFrame) {
93
98
  this.df = dataFrame;
@@ -418,7 +423,7 @@ export class PeptidesModel {
418
423
  }
419
424
 
420
425
  createAccordion(): DG.Accordion | null {
421
- const trueModel: PeptidesModel | undefined = grok.shell.t.temp[PeptidesModel.modelName];
426
+ const trueModel: PeptidesModel | undefined = grok.shell.t?.temp[PeptidesModel.modelName];
422
427
  if (!trueModel)
423
428
  return null;
424
429
 
@@ -519,6 +524,7 @@ export class PeptidesModel {
519
524
  const newColCat = newCol.categories;
520
525
  const newColData = newCol.getRawData();
521
526
  col = cols.addNew(newCol.name, newCol.type).init((i) => newColCat[newColData[i]]);
527
+ col.setTag(C.TAGS.ANALYSIS_COL, `${true}`);
522
528
  CR.setMonomerRenderer(col, this.alphabet);
523
529
  }
524
530
  this.df.name = name;
@@ -970,14 +976,22 @@ export class PeptidesModel {
970
976
  pane.expanded = true;
971
977
  };
972
978
 
973
- DG.debounce(selection.onChanged, 500).subscribe(() => {
979
+ selection.onChanged.subscribe(() => {
980
+ if (this.controlFire) {
981
+ this.controlFire = false;
982
+ return;
983
+ }
974
984
  if (!this.isUserChangedSelection)
975
985
  selection.copyFrom(getLatestSelection(), false);
976
986
  showAccordion();
977
987
  this.isUserChangedSelection = true;
978
988
  });
979
989
 
980
- DG.debounce(filter.onChanged, 500).subscribe(() => {
990
+ filter.onChanged.subscribe(() => {
991
+ if (this.controlFire) {
992
+ this.controlFire = false;
993
+ return;
994
+ }
981
995
  const lstViewer = this.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable | null;
982
996
  if (lstViewer !== null && typeof lstViewer.model !== 'undefined') {
983
997
  lstViewer.createLogoSummaryTableGrid();
@@ -994,6 +1008,13 @@ export class PeptidesModel {
994
1008
  this.df.selection.fireChanged();
995
1009
  if (fireFilterChanged)
996
1010
  this.df.filter.fireChanged();
1011
+
1012
+ // Fire bitset changed event again to update UI
1013
+ this.controlFire = true;
1014
+ this.df.selection.fireChanged();
1015
+ if (fireFilterChanged)
1016
+ this.df.filter.fireChanged();
1017
+
997
1018
  this.headerSelectedMonomers = calculateSelected(this.df);
998
1019
  }
999
1020
 
@@ -1162,6 +1183,7 @@ export class PeptidesModel {
1162
1183
  addNewCluster(clusterName: string): void {
1163
1184
  const newClusterCol = DG.Column.fromBitSet(clusterName, this.getCompoundBitset());
1164
1185
  newClusterCol.setTag(C.TAGS.CUSTOM_CLUSTER, '1');
1186
+ newClusterCol.setTag(C.TAGS.ANALYSIS_COL, `${true}`);
1165
1187
  this.df.columns.add(newClusterCol);
1166
1188
  this.analysisView.grid.col(newClusterCol.name)!.visible = false;
1167
1189
  }
@@ -1230,4 +1252,17 @@ export class PeptidesModel {
1230
1252
  }
1231
1253
  return selection;
1232
1254
  }
1255
+
1256
+ async addSequenceSpace(): Promise<void> {
1257
+ const seqSpaceParams: {table: DG.DataFrame, molecules: DG.Column, methodName: DimReductionMethods,
1258
+ similarityMetric: BitArrayMetrics | MmDistanceFunctionsNames, plotEmbeddings: boolean,
1259
+ sparseMatrixThreshold?: number, options?: IUMAPOptions | ITSNEOptions} =
1260
+ {table: this.df, molecules: this.df.getCol(this.settings.sequenceColumnName!), methodName: DimReductionMethods.UMAP,
1261
+ similarityMetric: MmDistanceFunctionsNames.MONOMER_CHEMICAL_DISTANCE, plotEmbeddings: true, sparseMatrixThreshold: 0.8,
1262
+ options: {}};
1263
+ const seqSpaceViewer: DG.ScatterPlotViewer | undefined = await grok.functions.call('Bio:sequenceSpaceTopMenu', seqSpaceParams);
1264
+ if (typeof seqSpaceViewer === 'undefined')
1265
+ return;
1266
+ this.analysisView.dockManager.dock(seqSpaceViewer, DG.DOCK_TYPE.RIGHT, this.findViewerNode(VIEWER_TYPE.LOGO_SUMMARY_TABLE), 'Sequence space');
1267
+ }
1233
1268
  }
@@ -1,14 +1,14 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import {runTests, tests, TestContext} from '@datagrok-libraries/utils/src/test';
3
3
 
4
- // import './tests/core';
4
+ import './tests/core';
5
5
  //FIXME: fails on CI; crashes browser
6
6
  // import './tests/peptide-space-test';
7
7
  import './tests/algorithms';
8
- // import './tests/viewers';
9
- // import './tests/widgets';
10
- // import './tests/table-view';
11
- // import './tests/model';
8
+ import './tests/viewers';
9
+ import './tests/widgets';
10
+ import './tests/table-view';
11
+ import './tests/model';
12
12
 
13
13
  export const _package = new DG.Package();
14
14
  export {tests};
package/src/tests/core.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
 
4
- import {category, test, expect, awaitCheck, delay} from '@datagrok-libraries/utils/src/test';
4
+ import {category, test, expect, awaitCheck, delay, after} from '@datagrok-libraries/utils/src/test';
5
5
 
6
6
  import {_package} from '../package-test';
7
7
  import {startAnalysis} from '../widgets/peptides';
@@ -38,15 +38,9 @@ category('Core', () => {
38
38
  model = await startAnalysis(
39
39
  simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, C.SCALING_METHODS.MINUS_LG);
40
40
  expect(model instanceof PeptidesModel, true, 'Model is null');
41
- let overlayInit = false;
42
- grok.log.debug('Waiting for overlay...');
43
- model!._analysisView!.grid.onAfterDrawOverlay.subscribe(() => {
44
- overlayInit = true;
45
- grok.log.debug('Overlay initialized');
46
- });
47
-
41
+
48
42
  model!.mutationCliffsSelection = {'11': ['D']};
49
- await delay(500);
43
+ await delay(3000)
50
44
  });
51
45
 
52
46
  test('Start analysis: сomplex', async () => {
@@ -64,16 +58,9 @@ category('Core', () => {
64
58
  model = await startAnalysis(
65
59
  complexActivityCol, complexAlignedSeqCol, null, complexTable, complexScaledCol, C.SCALING_METHODS.MINUS_LG);
66
60
  expect(model instanceof PeptidesModel, true, 'Model is null');
67
- let overlayInit = false;
68
- model!._analysisView!.grid.onAfterDrawOverlay.subscribe(() => {
69
- overlayInit = true;
70
- grok.log.debug('Overlay initialized');
71
- });
72
-
73
- if (model !== null)
74
- model.mutationCliffsSelection = {'13': ['-']};
75
61
 
76
- await delay(500);
62
+ model!.mutationCliffsSelection = {'13': ['-']};
63
+ await delay(3000)
77
64
  });
78
65
 
79
66
  test('Save and load project', async () => {
@@ -105,7 +92,7 @@ category('Core', () => {
105
92
  const sp = await grok.dapi.projects.save(project);
106
93
 
107
94
  v.close();
108
- await awaitCheck(() => typeof grok.shell.tableView('Peptides analysis') === 'undefined', 'Table never closed', 2000);
95
+ await awaitCheck(() => typeof grok.shell.tableView('Peptides analysis') === 'undefined', 'Table never closed', 3000);
109
96
 
110
97
  await sp.open();
111
98
  v = grok.shell.getTableView('Peptides analysis');
@@ -113,8 +100,6 @@ category('Core', () => {
113
100
  await grok.dapi.layouts.delete(sl);
114
101
  await grok.dapi.tables.delete(sti);
115
102
  await grok.dapi.projects.delete(sp);
116
-
117
- await delay(500);
118
103
  });
119
104
 
120
105
  test('Cluster stats - Benchmark HELM 5k', async () => {
@@ -1,6 +1,6 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
- import {category, test, before, expect, expectFloat, awaitCheck, delay} from '@datagrok-libraries/utils/src/test';
3
+ import {category, test, before, expect, expectFloat, awaitCheck, delay, after} from '@datagrok-libraries/utils/src/test';
4
4
  import {_package} from '../package-test';
5
5
  import {PeptidesModel, VIEWER_TYPE, getAggregatedColName} from '../model';
6
6
  import {startAnalysis} from '../widgets/peptides';
@@ -38,6 +38,8 @@ category('Model: Settings', () => {
38
38
  await delay(500);
39
39
  });
40
40
 
41
+ after(async () => await delay(3000));
42
+
41
43
  test('Activity scaling', async () => {
42
44
  const getError = (row: number, method: SCALING_METHODS): string =>
43
45
  `Activity mismatch at row ${row} for scaling method '${method}'`;
@@ -1,6 +1,6 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
- import {category, test, before, expect, delay} from '@datagrok-libraries/utils/src/test';
3
+ import {category, test, before, expect, delay, after} from '@datagrok-libraries/utils/src/test';
4
4
  import {_package} from '../package-test';
5
5
  import {CLUSTER_TYPE, PeptidesModel} from '../model';
6
6
  import {startAnalysis} from '../widgets/peptides';
@@ -39,6 +39,8 @@ category('Table view', () => {
39
39
  await delay(500);
40
40
  });
41
41
 
42
+ after(async () => await delay(3000));
43
+
42
44
  test('Tooltip', async () => {
43
45
  expect(model.showMonomerTooltip(firstPair.monomerOrCluster, 0, 0), true,
44
46
  `Couldn't structure for monomer ${firstPair.monomerOrCluster}`);
@@ -65,7 +67,6 @@ category('Table view', () => {
65
67
 
66
68
  // Select first monomer-position pair
67
69
  model.modifyMutationCliffsSelection(firstPair);
68
- await delay(500);
69
70
  expect(model.mutationCliffsSelection[firstPair.positionOrClusterType].includes(firstPair.monomerOrCluster), true,
70
71
  `Monomer ${firstPair.monomerOrCluster} is not selected at position ${firstPair.positionOrClusterType}`);
71
72
  expect(selection.trueCount, firstPair.mcCount, `Selection count is not equal to ${firstPair.mcCount} ` +
@@ -73,7 +74,6 @@ category('Table view', () => {
73
74
 
74
75
  // Select second monomer-position pair
75
76
  model.modifyMutationCliffsSelection(secondPair, {shiftPressed: true, ctrlPressed: false});
76
- await delay(500);
77
77
  expect(model.mutationCliffsSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), true,
78
78
  `Monomer ${secondPair.monomerOrCluster} is not selected at position ${secondPair.positionOrClusterType}`);
79
79
  expect(selection.trueCount, secondPair.mcCount + firstPair.mcCount, `Selection count is not equal ` +
@@ -82,7 +82,6 @@ category('Table view', () => {
82
82
 
83
83
  // Deselect second monomer-position pair
84
84
  model.modifyMutationCliffsSelection(secondPair, {shiftPressed: true, ctrlPressed: true});
85
- await delay(500);
86
85
  expect(model.mutationCliffsSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), false,
87
86
  `Monomer ${secondPair.monomerOrCluster} is still selected at position ${secondPair.positionOrClusterType} after deselection`);
88
87
  expect(selection.trueCount, firstPair.mcCount, `Selection count is not equal to ${firstPair.mcCount} ` +
@@ -90,7 +89,6 @@ category('Table view', () => {
90
89
 
91
90
  // Clear monomer-position selection
92
91
  model.initMutationCliffsSelection();
93
- await delay(500);
94
92
  for (const [position, selectedMonomers] of Object.entries(model.mutationCliffsSelection)) {
95
93
  expect(selectedMonomers.length, 0, `Selection is not empty for position ${position} after clearing ` +
96
94
  `monomer-position selection`);
@@ -99,7 +97,6 @@ category('Table view', () => {
99
97
 
100
98
  // Select first cluster
101
99
  model.modifyClusterSelection(firstCluster);
102
- await delay(500);
103
100
  expect(model.clusterSelection[firstCluster.positionOrClusterType].includes(firstCluster.monomerOrCluster), true,
104
101
  `Cluster ${firstCluster.monomerOrCluster} is not selected`);
105
102
  expect(selection.trueCount, firstCluster.count, `Selection count is not equal to ${firstCluster.count} for ` +
@@ -107,7 +104,6 @@ category('Table view', () => {
107
104
 
108
105
  // Select second cluster
109
106
  model.modifyClusterSelection(secondCluster, {shiftPressed: true, ctrlPressed: false});
110
- await delay(500);
111
107
  expect(model.clusterSelection[secondCluster.positionOrClusterType].includes(secondCluster.monomerOrCluster), true,
112
108
  `Cluster ${secondCluster.monomerOrCluster} is not selected`);
113
109
  expect(selection.trueCount, firstCluster.count + secondCluster.count, `Selection count is not equal to ` +
@@ -115,7 +111,6 @@ category('Table view', () => {
115
111
 
116
112
  // Deselect first cluster
117
113
  model.modifyClusterSelection(firstCluster, {shiftPressed: true, ctrlPressed: true});
118
- await delay(500);
119
114
  expect(model.clusterSelection[firstCluster.positionOrClusterType].includes(firstCluster.monomerOrCluster), false,
120
115
  `Cluster ${firstCluster.monomerOrCluster} is still selected after deselection`);
121
116
  expect(selection.trueCount, secondCluster.count, `Selection count is not equal to ${secondCluster.count} for ` +
@@ -123,7 +118,6 @@ category('Table view', () => {
123
118
 
124
119
  // Clear selection
125
120
  model.initClusterSelection();
126
- await delay(500);
127
121
  expect(model.isClusterSelectionEmpty, true, `Selection is not empty after clearing cluster selection`);
128
122
  expect(selection.trueCount, 0, `Selection count is not equal to 0 after clearing cluster selection`);
129
123
  });
@@ -136,7 +130,6 @@ category('Table view', () => {
136
130
 
137
131
  // Select by second monomer-position pair
138
132
  model.modifyInvariantMapSelection(secondPair);
139
- await delay(500);
140
133
  expect(model.invariantMapSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), true,
141
134
  `Monomer ${secondPair.monomerOrCluster} is not filtered at position ${secondPair.positionOrClusterType}`);
142
135
  expect(selection.trueCount, secondPair.imCount, `Filter count is not equal to ${secondPair.imCount} ` +
@@ -144,7 +137,6 @@ category('Table view', () => {
144
137
 
145
138
  // Select by first monomer-position pair
146
139
  model.modifyInvariantMapSelection(firstPair, {shiftPressed: true, ctrlPressed: false});
147
- await delay(500);
148
140
  expect(model.invariantMapSelection[firstPair.positionOrClusterType].includes(firstPair.monomerOrCluster), true,
149
141
  `Monomer ${firstPair.monomerOrCluster} is not filtered at position ${firstPair.positionOrClusterType}`);
150
142
  expect(selection.trueCount, secondPair.imCount, `Filter count is not equal to ${secondPair.imCount} ` +
@@ -152,7 +144,6 @@ category('Table view', () => {
152
144
 
153
145
  // Deselect filter for second monomer-position pair
154
146
  model.modifyInvariantMapSelection(secondPair, {shiftPressed: true, ctrlPressed: true});
155
- await delay(500);
156
147
  expect(model.invariantMapSelection[secondPair.positionOrClusterType].includes(secondPair.monomerOrCluster), false,
157
148
  `Monomer ${secondPair.monomerOrCluster} is still filtered at position ${secondPair.positionOrClusterType} after ` +
158
149
  `deselection`);
@@ -162,7 +153,6 @@ category('Table view', () => {
162
153
 
163
154
  // Clear selection
164
155
  model.initInvariantMapSelection();
165
- await delay(500);
166
156
  expect(selection.trueCount, 0, `Filter count is not equal to ${0} after clearing monomer-position filter`);
167
157
 
168
158
  for (const [position, filteredMonomers] of Object.entries(model.invariantMapSelection)) {
@@ -1,6 +1,6 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
 
3
- import {before, category, delay, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
3
+ import {after, before, category, delay, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
4
4
  import {aligned1} from './test-data';
5
5
  import {CLUSTER_TYPE, PeptidesModel, VIEWER_TYPE} from '../model';
6
6
  import {_package} from '../package-test';
@@ -50,6 +50,8 @@ category('Viewers: Monomer-Position', () => {
50
50
  await delay(500);
51
51
  });
52
52
 
53
+ after(async () => await delay(3000));
54
+
53
55
  test('Tooltip', async () => {
54
56
  const cellCoordinates = {col: '9', row: 6};
55
57
  const gc = mpViewer.viewerGrid.cell(cellCoordinates.col, cellCoordinates.row);
@@ -102,6 +104,8 @@ category('Viewers: Most Potent Residues', () => {
102
104
  await delay(500);
103
105
  });
104
106
 
107
+ after(async () => await delay(3000));
108
+
105
109
  test('Tooltip', async () => {
106
110
  const cellCoordinates = {col: 'Diff', row: 6};
107
111
  const gc = mprViewer.viewerGrid.cell(cellCoordinates.col, cellCoordinates.row);
@@ -139,6 +143,8 @@ category('Viewers: Logo Summary Table', () => {
139
143
  await delay(500);
140
144
  });
141
145
 
146
+ after(async () => await delay(3000));
147
+
142
148
  test('Properties', async () => {
143
149
  // Change Logo Summary Table Web Logo Mode property to full
144
150
  const webLogoMode = lstViewer.getProperty(LST_PROPERTIES.WEB_LOGO_MODE);
@@ -1,7 +1,7 @@
1
1
  import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
 
4
- import {category, test, before, expect, delay} from '@datagrok-libraries/utils/src/test';
4
+ import {category, test, before, expect, delay, after} from '@datagrok-libraries/utils/src/test';
5
5
  import {_package} from '../package-test';
6
6
  import {CLUSTER_TYPE, PeptidesModel, VIEWER_TYPE} from '../model';
7
7
  import {scaleActivity} from '../utils/misc';
@@ -40,6 +40,8 @@ category('Widgets: Settings', () => {
40
40
  await delay(500);
41
41
  });
42
42
 
43
+ after(async () => await delay(3000));
44
+
43
45
  test('UI', async () => {
44
46
  const settingsElements = getSettingsDialog(model);
45
47
 
@@ -83,6 +85,8 @@ category('Widgets: Distribution panel', () => {
83
85
  await delay(500);
84
86
  });
85
87
 
88
+ after(async () => await delay(3000));
89
+
86
90
  test('UI', async () => {
87
91
  getDistributionWidget(model.df, model);
88
92
  });
@@ -113,6 +117,8 @@ category('Widgets: Mutation cliffs', () => {
113
117
  await delay(500);
114
118
  });
115
119
 
120
+ after(async () => await delay(3000));
121
+
116
122
  test('UI', async () => {
117
123
  mutationCliffsWidget(model.df, model);
118
124
  });
@@ -143,6 +149,8 @@ category('Widgets: Actions', () => {
143
149
  await delay(500);
144
150
  });
145
151
 
152
+ after(async () => await delay(3000));
153
+
146
154
  test('New view', async () => {
147
155
  // Set compound bitset: filter out 2 rows and select 1 among them
148
156
  const filter = model.df.filter;
@@ -81,12 +81,16 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
81
81
  export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D, currentMonomer: string,
82
82
  currentPosition: string, invariantMapSelection: types.Selection, cellValue: number, bound: DG.Rect,
83
83
  color: number): void {
84
+ //FIXME: This is a hack, because `color` value sometimes comes incomplete. E.g. we found that here `color` value is
85
+ // 255 and its contrast color would be black, which is not visible on blue (color code) background. The full number
86
+ // is actually 4278190335.
87
+ color = DG.Color.fromHtml(DG.Color.toHtml(color));
84
88
  canvasContext.fillStyle = DG.Color.toHtml(color);
85
89
  canvasContext.fillRect(bound.x, bound.y, bound.width, bound.height);
86
90
  canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
87
91
  canvasContext.textAlign = 'center';
88
92
  canvasContext.textBaseline = 'middle';
89
- canvasContext.fillStyle = '#000';
93
+ canvasContext.fillStyle = DG.Color.toHtml(DG.Color.getContrastColor(color));
90
94
  canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
91
95
 
92
96
  const monomerSelection = invariantMapSelection[currentPosition];
@@ -114,18 +118,19 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
114
118
  drawOptions.symbolStyle ??= '16px Roboto, Roboto Local, sans-serif';
115
119
  drawOptions.upperLetterHeight ??= 12.2;
116
120
  drawOptions.upperLetterAscent ??= 0.25;
117
- drawOptions.marginVertical ??= 5;
118
- drawOptions.marginHorizontal ??= 5;
121
+ drawOptions.marginVertical ??= 2;
122
+ drawOptions.marginHorizontal ??= 2;
123
+ drawOptions.selectionWidth ??= 1;
119
124
  drawOptions.textHeight ??= 13;
120
125
  drawOptions.headerStyle ??= `bold ${drawOptions.textHeight * pr}px Roboto, Roboto Local, sans-serif`;
121
126
 
122
127
  const totalSpace = (sortedOrder.length - 1) * drawOptions.upperLetterAscent; // Total space between letters
123
128
  const barHeight = (bounds.height - 2 * drawOptions.marginVertical - totalSpace - 1.25 * drawOptions.textHeight) * pr;
124
129
  const leftShift = drawOptions.marginHorizontal * 2;
125
- const barWidth = (bounds.width - leftShift * 2) * pr;
130
+ const barWidth = (bounds.width - (leftShift + drawOptions.marginHorizontal)) * pr;
126
131
  const xStart = (bounds.x + leftShift) * pr;
127
- const selectionWidth = 4 * pr;
128
- const xSelection = (bounds.x + 3) * pr;
132
+ const selectionWidth = Math.min(drawOptions.selectionWidth * pr, 1);
133
+ const xSelection = (bounds.x + 1) * pr;
129
134
  let currentY = (bounds.y + drawOptions.marginVertical) * pr;
130
135
 
131
136
  const monomerBounds: { [monomer: string]: DG.Rect } = {};
@@ -43,6 +43,7 @@ export enum TAGS {
43
43
  MULTIPLE_VIEWS = 'isMultipleViews',
44
44
  IDENTITY_TEMPLATE = 'Identity template',
45
45
  SIMILARITY_TEMPLATE = 'Similarity template',
46
+ ANALYSIS_COL = 'isAnalysisCol',
46
47
  }
47
48
 
48
49
  export enum SEM_TYPES {
package/src/utils/misc.ts CHANGED
@@ -36,7 +36,7 @@ export function scaleActivity(activityCol: DG.Column<number>, scaling: C.SCALING
36
36
  const val = activityColData[i];
37
37
  return val === DG.FLOAT_NULL || val === DG.INT_NULL ? val : formula(val);
38
38
  });
39
-
39
+ scaledCol.setTag(C.TAGS.ANALYSIS_COL, `${true}`);
40
40
  return scaledCol;
41
41
  }
42
42
 
@@ -131,4 +131,5 @@ export function setGridProps(grid: DG.Grid): void {
131
131
  grid.props.showRowHeader = false;
132
132
  grid.props.showCurrentRowIndicator = false;
133
133
  grid.root.style.width = '100%';
134
+ grid.root.style.maxWidth = '100%';
134
135
  }