@datagrok/bio 2.12.16 → 2.12.18

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -2
  2. package/dist/79.js.map +1 -1
  3. package/dist/package-test.js +5 -5
  4. package/dist/package-test.js.map +1 -1
  5. package/dist/package.js +3 -3
  6. package/dist/package.js.map +1 -1
  7. package/package.json +6 -6
  8. package/src/package-test.ts +1 -1
  9. package/src/package.ts +38 -44
  10. package/src/tests/monomer-libraries-tests.ts +1 -4
  11. package/src/tests/renderers-monomer-placer-tests.ts +9 -8
  12. package/src/tests/renderers-test.ts +1 -1
  13. package/src/tests/scoring.ts +2 -2
  14. package/src/tests/substructure-filters-tests.ts +4 -2
  15. package/src/tests/to-atomic-level-tests.ts +1 -1
  16. package/src/tests/utils.ts +15 -0
  17. package/src/utils/cell-renderer.ts +45 -70
  18. package/src/utils/{poly-tool/cyclized.ts → cyclized.ts} +3 -7
  19. package/src/utils/helm-to-molfile/converter/converter.ts +10 -5
  20. package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +9 -9
  21. package/src/utils/helm-to-molfile/converter/polymer.ts +10 -3
  22. package/src/utils/monomer-cell-renderer.ts +18 -8
  23. package/src/utils/monomer-lib/lib-manager.ts +56 -18
  24. package/src/utils/monomer-lib/library-file-manager/event-manager.ts +15 -9
  25. package/src/utils/monomer-lib/library-file-manager/file-manager.ts +78 -59
  26. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +3 -1
  27. package/src/utils/monomer-lib/library-file-manager/ui.ts +52 -47
  28. package/src/utils/monomer-lib/monomer-lib.ts +91 -10
  29. package/src/utils/sequence-to-mol.ts +7 -7
  30. package/src/widgets/bio-substructure-filter-helm.ts +5 -4
  31. package/src/widgets/bio-substructure-filter.ts +2 -3
  32. package/webpack.config.js +3 -0
  33. package/src/utils/poly-tool/const.ts +0 -40
  34. package/src/utils/poly-tool/csv-to-json-monomer-lib-converter.ts +0 -40
  35. package/src/utils/poly-tool/monomer-lib-handler.ts +0 -115
  36. package/src/utils/poly-tool/transformation.ts +0 -320
  37. package/src/utils/poly-tool/ui.ts +0 -59
  38. package/src/utils/poly-tool/utils.ts +0 -20
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Aleksandr Tanas",
6
6
  "email": "atanas@datagrok.ai"
7
7
  },
8
- "version": "2.12.16",
8
+ "version": "2.12.18",
9
9
  "description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
10
10
  "repository": {
11
11
  "type": "git",
@@ -34,12 +34,12 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@biowasm/aioli": "^3.1.0",
37
- "@datagrok-libraries/bio": "^5.40.8",
37
+ "@datagrok-libraries/bio": "^5.41.2",
38
38
  "@datagrok-libraries/chem-meta": "^1.2.5",
39
39
  "@datagrok-libraries/math": "^1.1.5",
40
40
  "@datagrok-libraries/ml": "^6.6.5",
41
41
  "@datagrok-libraries/tutorials": "^1.3.12",
42
- "@datagrok-libraries/utils": "^4.2.0",
42
+ "@datagrok-libraries/utils": "^4.2.5",
43
43
  "@webgpu/types": "^0.1.40",
44
44
  "ajv": "^8.12.0",
45
45
  "ajv-errors": "^3.0.0",
@@ -55,9 +55,9 @@
55
55
  "wu": "latest"
56
56
  },
57
57
  "devDependencies": {
58
- "@datagrok/chem": "^1.9.0",
59
- "@datagrok/dendrogram": "^1.2.27",
60
- "@datagrok/helm": "^2.1.30",
58
+ "@datagrok/chem": "^1.9.2",
59
+ "@datagrok/dendrogram": "^1.2.29",
60
+ "@datagrok/helm": "^2.1.34",
61
61
  "@types/node": "^17.0.24",
62
62
  "@types/wu": "latest",
63
63
  "@typescript-eslint/eslint-plugin": "latest",
@@ -23,7 +23,7 @@ import './tests/WebLogo-project-tests';
23
23
  import './tests/WebLogo-layout-tests';
24
24
  import './tests/checkInputColumn-tests';
25
25
  import './tests/similarity-diversity-tests';
26
- import './tests/substructure-filters-tests';
26
+ // import './tests/substructure-filters-tests';
27
27
  import './tests/pepsea-tests';
28
28
  import './tests/viewers';
29
29
  import './tests/seq-handler-tests';
package/src/package.ts CHANGED
@@ -3,6 +3,8 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
+ import '@datagrok-libraries/bio/src/types/helm';
7
+
6
8
  import {Options} from '@datagrok-libraries/utils/src/type-declarations';
7
9
  import {DimReductionBaseEditor, PreprocessFunctionReturnType}
8
10
  from '@datagrok-libraries/ml/src/functionEditors/dimensionality-reduction-editor';
@@ -55,13 +57,9 @@ import {SplitToMonomersFunctionEditor} from './function-edtiors/split-to-monomer
55
57
  import {splitToMonomersUI} from './utils/split-to-monomers';
56
58
  import {MonomerCellRenderer} from './utils/monomer-cell-renderer';
57
59
  import {BioPackage, BioPackageProperties} from './package-types';
58
- // import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
59
60
  import {getCompositionAnalysisWidget} from './widgets/composition-analysis-widget';
60
61
  import {MacromoleculeColumnWidget} from './utils/macromolecule-column-widget';
61
62
  import {addCopyMenuUI} from './utils/context-menu';
62
- import {getPolyToolDialog} from './utils/poly-tool/ui';
63
- import {PolyToolCsvLibHandler} from './utils/poly-tool/csv-to-json-monomer-lib-converter';
64
- import {_setPeptideColumn} from './utils/poly-tool/utils';
65
63
  import {getRegionDo} from './utils/get-region';
66
64
  import {GetRegionApp} from './apps/get-region-app';
67
65
  import {GetRegionFuncEditor} from './utils/get-region-func-editor';
@@ -77,7 +75,8 @@ import {DimReductionMethods} from '@datagrok-libraries/ml/src/multi-column-dimen
77
75
  import {
78
76
  ITSNEOptions, IUMAPOptions
79
77
  } from '@datagrok-libraries/ml/src/multi-column-dimensionality-reduction/multi-column-dim-reducer';
80
- import {CyclizedNotationProvider} from './utils/poly-tool/cyclized';
78
+ import {CyclizedNotationProvider} from './utils/cyclized';
79
+ import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
81
80
 
82
81
  export const _package = new BioPackage();
83
82
 
@@ -87,8 +86,8 @@ export const _package = new BioPackage();
87
86
  //name: getMonomerLibHelper
88
87
  //description:
89
88
  //output: object result
90
- export function getMonomerLibHelper(): IMonomerLibHelper {
91
- return MonomerLibManager.instance;
89
+ export async function getMonomerLibHelper(): Promise<IMonomerLibHelper> {
90
+ return await MonomerLibManager.getInstance();
92
91
  }
93
92
 
94
93
  export let hydrophobPalette: SeqPaletteCustom | null = null;
@@ -105,12 +104,20 @@ export class SeqPaletteCustom implements SeqPalette {
105
104
  }
106
105
  }
107
106
 
107
+ let monomerLib: IMonomerLib | null = null;
108
+
108
109
  //tags: init
109
110
  export async function initBio() {
110
- _package.logger.debug('Bio: initBio(), started');
111
+ const logPrefix = 'Bio: initBio()';
112
+ _package.logger.debug(`${logPrefix}, start`);
111
113
  const module = await grok.functions.call('Chem:getRdKitModule');
114
+ const t1: number = window.performance.now();
112
115
  await Promise.all([
113
- (async () => { await MonomerLibManager.instance.loadLibraries(); })(),
116
+ (async () => {
117
+ const monomerLibManager = await MonomerLibManager.getInstance();
118
+ await monomerLibManager.loadLibraries();
119
+ monomerLib = monomerLibManager.getBioLib();
120
+ })(),
114
121
  (async () => {
115
122
  const pkgProps = await _package.getProperties();
116
123
  const bioPkgProps = new BioPackageProperties(pkgProps);
@@ -118,9 +125,10 @@ export async function initBio() {
118
125
  })(),
119
126
  ]).finally(() => {
120
127
  _package.completeInit();
128
+ const t2: number = window.performance.now();
129
+ _package.logger.debug(`${logPrefix}, loading ET: ${t2 - t1} ms`);
121
130
  });
122
131
 
123
- const monomerLib = MonomerLibManager.instance.getBioLib();
124
132
  const monomers: string[] = [];
125
133
  const logPs: number[] = [];
126
134
 
@@ -160,10 +168,16 @@ export function sequenceTooltip(col: DG.Column): DG.Widget<any> {
160
168
  return resWidget;
161
169
  }
162
170
 
171
+ // Keep for backward compatibility
163
172
  //name: getBioLib
164
173
  //output: object monomerLib
165
174
  export function getBioLib(): IMonomerLib {
166
- return MonomerLibManager.instance.getBioLib();
175
+ return monomerLib!;
176
+ }
177
+
178
+ // For sync internal use, on initialized package
179
+ export function getMonomerLib(): IMonomerLib | null {
180
+ return monomerLib!;
167
181
  }
168
182
 
169
183
  //name: getSeqHandler
@@ -572,7 +586,8 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, molecules: DG.Co
572
586
  export async function toAtomicLevel(table: DG.DataFrame, seqCol: DG.Column, nonlinear: boolean): Promise<void> {
573
587
  const pi = DG.TaskBarProgressIndicator.create('Converting to atomic level ...');
574
588
  try {
575
- await sequenceToMolfile(table, seqCol, nonlinear);
589
+ const monomerLib = (await getMonomerLibHelper()).getBioLib();
590
+ await sequenceToMolfile(table, seqCol, nonlinear, monomerLib);
576
591
  } finally {
577
592
  pi.close();
578
593
  }
@@ -685,19 +700,6 @@ export function convertDialog() {
685
700
  convert(col);
686
701
  }
687
702
 
688
- //top-menu: Bio | Convert | PolyTool
689
- //name: polyTool
690
- //description: Perform cyclization of polymers
691
- export async function polyTool(): Promise<void> {
692
- let dialog: DG.Dialog;
693
- try {
694
- dialog = await getPolyToolDialog();
695
- dialog.show();
696
- } catch (err: any) {
697
- grok.shell.warning('To run PolyTool, open a dataframe with macromolecules');
698
- }
699
- }
700
-
701
703
  //name: monomerCellRenderer
702
704
  //tags: cellRenderer
703
705
  //meta.cellType: Monomer
@@ -1010,25 +1012,6 @@ export async function demoBioHelmMsaSequenceSpace(): Promise<void> {
1010
1012
  await demoBio05UI();
1011
1013
  }
1012
1014
 
1013
- //name: polyToolColumnChoice
1014
- //input: dataframe df [Input data table]
1015
- //input: column macroMolecule
1016
- export async function polyToolColumnChoice(df: DG.DataFrame, macroMolecule: DG.Column): Promise<void> {
1017
- _setPeptideColumn(macroMolecule);
1018
- await grok.data.detectSemanticTypes(df);
1019
- }
1020
-
1021
- //name: createMonomerLibraryForPolyTool
1022
- //input: file file
1023
- export async function createMonomerLibraryForPolyTool(file: DG.FileInfo) {
1024
- const fileContent = await file.readAsString();
1025
- const libHandler = new PolyToolCsvLibHandler(file.fileName, fileContent);
1026
- const libObject = await libHandler.getJson();
1027
- const jsonFileName = file.fileName.replace(/\.csv$/, '.json');
1028
- const jsonFileContent = JSON.stringify(libObject, null, 2);
1029
- DG.Utils.download(jsonFileName, jsonFileContent);
1030
- }
1031
-
1032
1015
  //name: SDF to JSON Library
1033
1016
  //input: dataframe table
1034
1017
  export async function sdfToJsonLib(table: DG.DataFrame) {
@@ -1048,6 +1031,17 @@ export async function detectMacromoleculeProbe(file: DG.FileInfo, colName: strin
1048
1031
  await detectMacromoleculeProbeDo(csv, colName, probeCount);
1049
1032
  }
1050
1033
 
1034
+ //name: getMolFromHelm
1035
+ //input: dataframe df
1036
+ //input: column helmCol
1037
+ //input: bool chiralityEngine
1038
+ //output: column result
1039
+ export async function getMolFromHelm(
1040
+ df: DG.DataFrame, helmCol: DG.Column<string>, chiralityEngine?: boolean
1041
+ ): Promise<DG.Column<string>> {
1042
+ return getMolColumnFromHelm(df, helmCol, chiralityEngine);
1043
+ }
1044
+
1051
1045
  // -- Custom notation providers --
1052
1046
 
1053
1047
  //name: applyNotationProviderForCyclized
@@ -8,8 +8,6 @@ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/sr
8
8
  import {
9
9
  getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
10
10
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
11
- import {MonomerLibFileManager} from '../utils/monomer-lib/library-file-manager/file-manager';
12
- import {MonomerLibFileEventManager} from '../utils/monomer-lib/library-file-manager/event-manager';
13
11
 
14
12
 
15
13
  category('monomerLibraries', () => {
@@ -51,8 +49,7 @@ category('monomerLibraries', () => {
51
49
  test('empty', async () => {
52
50
  // exclude all monomer libraries for empty set
53
51
  const libSettings = await getUserLibSettings();
54
- const libFileEventManager = MonomerLibFileEventManager.getInstance();
55
- const libFileManager = await MonomerLibFileManager.getInstance(libFileEventManager);
52
+ const libFileManager = await monomerLibHelper.getFileManager();
56
53
 
57
54
  let libFnList = libFileManager.getValidLibraryPaths();
58
55
  if (libFnList.length === 0)
@@ -8,8 +8,7 @@ import {category, test} from '@datagrok-libraries/utils/src/test';
8
8
  import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
9
9
  import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
10
10
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
11
-
12
- import {MonomerLibManager} from '../utils/monomer-lib/lib-manager';
11
+ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
13
12
 
14
13
  import {_package} from '../package-test';
15
14
 
@@ -45,7 +44,7 @@ category('renderers: monomerPlacer', () => {
45
44
  'id1,m1-M-m3-mon4-mon5-N-T-MON8-N9\n' +
46
45
  'id2,m1-mon2-m3-mon4-mon5-Num--MON8-N9\n' +
47
46
  'id3,\n' + // empty
48
- 'id4,mon1-M-mon3-mon4-mon5---MON8-N9\n',
47
+ 'id4,mon1-M-mon3-mon4-mon5---MON8-N9\n', // [ 5, 38, 71, 104, 137, 170, 203, 236, 269, 295 ]
49
48
  testList: [
50
49
  {src: {row: 0, x: -1}, tgt: {pos: null}},
51
50
  {src: {row: 1, x: 0}, tgt: {pos: null}},
@@ -59,7 +58,7 @@ category('renderers: monomerPlacer', () => {
59
58
  {src: {row: 2, x: 20}, tgt: {pos: null}}, // empty value
60
59
  {src: {row: 3, x: 170}, tgt: {pos: 4}},
61
60
  {src: {row: 3, x: 200}, tgt: {pos: 5}},
62
- {src: {row: 3, x: 282}, tgt: {pos: null}},
61
+ {src: {row: 3, x: 297}, tgt: {pos: null}},
63
62
  ]
64
63
  },
65
64
  fastaMsa: {
@@ -88,6 +87,8 @@ id3,QHIRE--LT
88
87
 
89
88
  for (const [testName, testData] of Object.entries(tests)) {
90
89
  test(`getPosition-${testName}`, async () => {
90
+ const libHelper = await getMonomerLibHelper();
91
+ const monomerLib = libHelper.getBioLib();
91
92
  const df: DG.DataFrame = DG.DataFrame.fromCsv(testData.csv);
92
93
  await grok.data.detectSemanticTypes(df);
93
94
  const seqCol: DG.Column = df.getCol('seq');
@@ -95,7 +96,7 @@ id3,QHIRE--LT
95
96
  const monLength: number = 3;
96
97
  const charWidth: number = 7;
97
98
  const sepWidth: number = 12;
98
- const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, () => {
99
+ const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger, () => {
99
100
  const sh = SeqHandler.forColumn(seqCol);
100
101
  return {
101
102
  seqHandler: sh,
@@ -103,18 +104,18 @@ id3,QHIRE--LT
103
104
  separatorWidth: sepWidth,
104
105
  monomerToShort: monomerToShort,
105
106
  monomerLengthLimit: monLength,
106
- monomerLib: MonomerLibManager.instance.getBioLib(),
107
107
  };
108
108
  });
109
109
 
110
+ const width: number = 10000;
110
111
  const testList = testData.testList;
111
112
  // simulate rendering
112
113
  for (let rowI: number = 0; rowI < seqCol.length; ++rowI)
113
- colTemp.getCellMonomerLengths(rowI);
114
+ colTemp.getCellMonomerLengths(rowI, 10000);
114
115
 
115
116
  const errorList: string[] = [];
116
117
  for (const [test, _testI] of wu.enumerate(testList)) {
117
- const res = {pos: colTemp.getPosition(test.src.row, test.src.x)};
118
+ const res = {pos: colTemp.getPosition(test.src.row, test.src.x, width)};
118
119
  if (test.tgt.pos != res.pos) {
119
120
  errorList.push(`Test src ${JSON.stringify(test.src)} expected tgt ${JSON.stringify(test.tgt)},` +
120
121
  ` but get ${JSON.stringify({res})}`);
@@ -56,7 +56,7 @@ category('renderers', () => {
56
56
 
57
57
  test('scatterPlotTooltip', async () => {
58
58
  await _testScatterPlotTooltip();
59
- });
59
+ }, {skipReason: 'GROK-15679'});
60
60
 
61
61
  async function _rendererMacromoleculeFasta() {
62
62
  const csv: string = await grok.dapi.files.readAsText('System:AppData/Bio/samples/FASTA.csv');
@@ -4,9 +4,9 @@ import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {category, test, expectFloat, before, after} from '@datagrok-libraries/utils/src/test';
6
6
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
- import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
7
+ import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
8
 
9
- import {sequenceIdentityScoring, sequenceSimilarityScoring} from '../package';
9
+ import {getMonomerLibHelper, sequenceIdentityScoring, sequenceSimilarityScoring} from '../package';
10
10
  import {
11
11
  getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
12
12
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
@@ -185,7 +185,8 @@ category('bio-substructure-filters', async () => {
185
185
  dlg.close();
186
186
  }
187
187
  await filter.awaitRendered();
188
- });
188
+ await delay(3000); //TODO: await for grid.onLookChanged
189
+ }, {skipReason: 'GROK-15678'});
189
190
 
190
191
  // Generates unhandled exception accessing isFiltering before bioFilter created
191
192
  test('helm-view', async () => {
@@ -308,7 +309,8 @@ category('bio-substructure-filters', async () => {
308
309
  }
309
310
  await Promise.all([f1.awaitRendered(), f2.awaitRendered()]);
310
311
  await awaitGrid(view.grid);
311
- });
312
+ await delay(3000); //TODO: await for grid.onLookChanged
313
+ }, {skipReason: 'GROK-15678'});
312
314
 
313
315
  // two seq columns
314
316
 
@@ -7,7 +7,7 @@ import wu from 'wu';
7
7
 
8
8
  import {before, after, category, test, expectArray, expect} from '@datagrok-libraries/utils/src/test';
9
9
  import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
10
- import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
10
+ import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
11
11
  import {ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
12
12
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
13
13
  import {
@@ -2,10 +2,12 @@ import * as DG from 'datagrok-api/dg';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
 
4
4
  import {delay, expect, testEvent} from '@datagrok-libraries/utils/src/test';
5
+ import {asRenderer, IRenderer, isRenderer} from '@datagrok-libraries/bio/src/types/renderer';
5
6
 
6
7
  import {startDockerContainer} from '../utils/docker';
7
8
 
8
9
  import {_package} from '../package-test';
10
+ import {CellRendererBackBase, getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
9
11
 
10
12
  export async function loadFileAsText(name: string): Promise<string> {
11
13
  return await _package.files.readAsText(name);
@@ -38,4 +40,17 @@ export async function awaitGrid(grid: DG.Grid, timeout: number = 5000): Promise<
38
40
  await delay(0);
39
41
  await testEvent(grid.onAfterDrawContent, () => {},
40
42
  () => { grid.invalidate(); }, timeout);
43
+
44
+ const colCount = grid.columns.length;
45
+ for (let colI = 0; colI < colCount; ++colI) {
46
+ const gridCol = grid.columns.byIndex(colI);
47
+ if (gridCol) {
48
+ const gridCell = grid.cell(gridCol.name, 0);
49
+ const [_gridCol, _tableCol, temp] =
50
+ getGridCellRendererBack<void, CellRendererBackBase<void>>(gridCell);
51
+
52
+ const renderer = asRenderer(temp.rendererBack);
53
+ if (renderer) await renderer.awaitRendered();
54
+ }
55
+ }
41
56
  }
@@ -3,7 +3,6 @@ import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import wu from 'wu';
6
- import {Unsubscribable} from 'rxjs';
7
6
 
8
7
  import {printLeftOrCentered, DrawStyle, TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
9
8
  import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
@@ -22,7 +21,8 @@ import {GapOriginals, SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-ha
22
21
  import {ISeqSplitted, SeqSplittedBase} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
23
22
  import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
24
23
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
25
- import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
24
+ import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/types';
25
+ import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
26
26
 
27
27
  import {
28
28
  Temps as mmcrTemps, Tags as mmcrTags,
@@ -30,14 +30,16 @@ import {
30
30
  } from '../utils/cell-renderer-consts';
31
31
  import * as C from './constants';
32
32
 
33
- import {_package, getBioLib} from '../package';
33
+ import {_package, getMonomerLib} from '../package';
34
34
 
35
35
  type TempType = { [tagName: string]: any };
36
36
 
37
37
  const undefinedColor = 'rgb(100,100,100)';
38
38
  const monomerToShortFunction: MonomerToShortFunc = monomerToShort;
39
39
 
40
- function getUpdatedWidth(grid: DG.Grid | null, g: CanvasRenderingContext2D, x: number, w: number, dpr: number): number {
40
+ function getUpdatedWidth(
41
+ grid: DG.Grid | null | undefined, g: CanvasRenderingContext2D, x: number, w: number, dpr: number
42
+ ): number {
41
43
  return !!grid ? Math.max(Math.min(grid.canvas.width / dpr - x, w)) : Math.max(g.canvas.width / dpr - x, 0);
42
44
  }
43
45
 
@@ -63,27 +65,6 @@ type RendererGridCellTemp = {
63
65
  [mmcrTemps.monomerPlacer]: MonomerPlacer
64
66
  }
65
67
 
66
- function getRendererFridCellTempTemp(gridCell: DG.GridCell): RendererGridCellTemp {
67
- /** Primarily store/get MonomerPlacer at GridColumn, fallback at (Table) Column for scatter plot tooltip */
68
- let temp: RendererGridCellTemp | null = null;
69
-
70
- let gridCol: DG.GridColumn | null = null;
71
- try { gridCol = gridCell.gridColumn; } catch { gridCol = null; }
72
- temp = gridCol && gridCol.dart ? gridCol.temp as RendererGridCellTemp : null;
73
-
74
- if (!temp) {
75
- let tableCol: DG.Column | null = null;
76
- try { tableCol = gridCell.cell.column; } catch { tableCol = null; }
77
- if (!tableCol) {
78
- const k = 42;
79
- }
80
- temp = tableCol ? tableCol.temp as RendererGridCellTemp : null;
81
- }
82
- if (temp === null)
83
- throw new Error(`Monomer placer store (GridColumn or Column) not found.`);
84
- return temp;
85
- }
86
-
87
68
  export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
88
69
  private padding: number = 5;
89
70
 
@@ -105,9 +86,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
105
86
  // if (gridCell.cell.column.getTag(bioTAGS.aligned) !== ALIGNMENT.SEQ_MSA)
106
87
  // return;
107
88
 
108
- const tableCol: DG.Column = gridCell.cell.column;
109
- //const tableColTemp: TempType = tableCol.temp;
110
- const seqColTemp: MonomerPlacer = getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer];
89
+ const [_gridCol, tableCol, temp] =
90
+ getGridCellRendererBack<string, MonomerPlacer>(gridCell);
91
+ const seqColTemp: MonomerPlacer = temp['rendererBack'];
111
92
  if (!seqColTemp) return; // Can do nothing without precalculated data
112
93
 
113
94
  const gridCellBounds: DG.Rect = gridCell.bounds;
@@ -119,9 +100,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
119
100
  // maxLengthWordsSum[posI] = maxLengthWordsSum[posI - 1] + maxLengthWords[posI];
120
101
  // const maxIndex = maxLengthWords.length;
121
102
  const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCellBounds.x);
122
- const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX);
103
+ const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX, gridCellBounds.width);
123
104
 
124
- const seqCList: SeqSplittedBase = SeqHandler.forColumn(seqColTemp.col)
105
+ const seqCList: SeqSplittedBase = SeqHandler.forColumn(tableCol)
125
106
  .getSplitted(gridCell.tableRowIndex!).canonicals;
126
107
  if (left !== null && left < seqCList.length) {
127
108
  const monomerSymbol: string = seqCList[left];
@@ -133,8 +114,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
133
114
  const alphabet = sh.alphabet ?? ALPHABET.UN;
134
115
  const polymerType = alphabetPolymerTypes[alphabet as ALPHABET];
135
116
 
136
- const lib: IMonomerLib = seqColTemp.props.monomerLib!;
137
- return lib.getTooltip(polymerType, monomerSymbol);
117
+ const lib: IMonomerLib | null = getMonomerLib();
118
+ return lib ? lib.getTooltip(polymerType, monomerSymbol) : ui.divText('Monomer library is not available');
138
119
  })();
139
120
  }
140
121
  tooltipElements.push(monomerDiv);
@@ -162,23 +143,17 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
162
143
  _cellStyle: DG.GridCellStyle
163
144
  ): void {
164
145
  const logPrefix: string = 'MacromoleculeSequenceCellRenderer.render()';
146
+
147
+ const dpr = window.devicePixelRatio;
148
+ const [gridCol, tableCol, _temp] =
149
+ getGridCellRendererBack<string, MonomerPlacer>(gridCell);
150
+ if (!tableCol) return;
151
+ const tableColTemp: TempType = tableCol.temp;
152
+
165
153
  let gapLength = 0;
166
154
  const msaGapLength = 8;
167
155
  let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
168
156
 
169
- // TODO: Store temp data to GridColumn
170
- // Now the renderer requires data frame table Column underlying GridColumn
171
- let grid: DG.Grid | undefined = undefined;
172
- try { grid = gridCell.grid; } catch (err: any) {
173
- grid = undefined;
174
- const [errMsg, errStack] = errInfo(err);
175
- _package.logger.error(errMsg, undefined, errStack);
176
- }
177
- const tableCol: DG.Column = gridCell.cell.column;
178
- if (!grid || !tableCol) return;
179
-
180
- const tableColTemp: TempType = tableCol.temp;
181
-
182
157
  // Cell renderer settings
183
158
  const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
184
159
  const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
@@ -190,44 +165,41 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
190
165
  (!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
191
166
  }
192
167
 
193
- let seqColTemp: MonomerPlacer = getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer];
168
+ const [_gc, _tc, temp] =
169
+ getGridCellRendererBack<string, MonomerPlacer>(gridCell);
170
+ let seqColTemp: MonomerPlacer = temp.rendererBack;
194
171
  if (!seqColTemp) {
195
- seqColTemp = new MonomerPlacer(grid, tableCol,
172
+ seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
196
173
  () => {
197
174
  const sh = SeqHandler.forColumn(tableCol);
198
175
  return {
199
176
  seqHandler: sh,
200
177
  monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
201
178
  monomerToShort: monomerToShortFunction, monomerLengthLimit: maxLengthOfMonomer,
202
- monomerLib: getBioLib()
203
179
  };
204
180
  });
205
181
  }
206
182
 
207
- if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
208
- gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
209
- // this event means that the mm renderer settings have changed, particularly monomer representation and max width.
210
- seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
211
- seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
212
- tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
213
- }
214
-
215
- const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
216
- seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!);
217
- const _maxIndex = maxLengthWords.length;
218
-
219
- // Store updated seqColTemp to the col temp
220
- if (seqColTemp.updated) getRendererFridCellTempTemp(gridCell)[mmcrTemps.monomerPlacer] = seqColTemp;
221
-
222
183
  g.save();
223
184
  try {
224
- const dpr = window.devicePixelRatio;
225
- const grid = gridCell.gridRow !== -1 ? gridCell.grid : null;
185
+ if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
186
+ gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
187
+ // this event means that the mm renderer settings have changed,
188
+ // particularly monomer representation and max width.
189
+ seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
190
+ seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
191
+ tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
192
+ }
193
+
194
+ const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
195
+ seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!, w);
196
+ const _maxIndex = maxLengthWords.length;
197
+
226
198
  const value: any = gridCell.cell.value;
227
199
  const rowIdx = gridCell.cell.rowIndex;
228
200
  const paletteType = tableCol.getTag(bioTAGS.alphabet);
229
201
  const minDistanceRenderer = 50;
230
- w = getUpdatedWidth(grid, g, x, w, dpr);
202
+ w = getUpdatedWidth(gridCol?.grid, g, x, w, dpr);
231
203
  g.beginPath();
232
204
  g.rect(x + this.padding, y + this.padding, w - this.padding - 1, h - this.padding * 2);
233
205
  g.clip();
@@ -241,7 +213,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
241
213
  const palette = getPaletteByType(paletteType);
242
214
 
243
215
  const separator = tableCol.getTag(bioTAGS.separator) ?? '';
244
- const splitLimit = w / 5;
216
+ const minMonWidth = seqColTemp.props.separatorWidth + 1 * seqColTemp.props.monomerCharWidth;
217
+ const splitLimit = w / minMonWidth;
245
218
  const sh = SeqHandler.forColumn(tableCol);
246
219
 
247
220
  const tempReferenceSequence: string | null = tableColTemp[tempTAGS.referenceSequence];
@@ -265,7 +238,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
265
238
  if (aligned && aligned.includes('MSA') && units == NOTATION.SEPARATOR)
266
239
  drawStyle = DrawStyle.MSA;
267
240
 
268
- for (let posIdx: number = 0; posIdx < subParts.length; ++posIdx) {
241
+ const visibleSeqLength = Math.min(subParts.length, splitLimit);
242
+ for (let posIdx: number = 0; posIdx < visibleSeqLength; ++posIdx) {
269
243
  const amino: string = subParts.getOriginal(posIdx);
270
244
  color = palette.get(amino);
271
245
  g.fillStyle = undefinedColor;
@@ -277,8 +251,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
277
251
  if (minDistanceRenderer > w) break;
278
252
  }
279
253
  } catch (err: any) {
280
- const errMsg: string = err instanceof Error ? err.message : !!err ? err.toString() : 'Error \'undefined\'';
281
- _package.logger.error(`Bio: MacromoleculeSequenceCellRenderer.render() error: ${errMsg}`);
254
+ const [errMsg, errStack] = errInfo(err);
255
+ seqColTemp.logger.error(errMsg, undefined, errStack);
256
+ seqColTemp.errors.push(err);
282
257
  //throw err; // Do not throw to prevent disabling renderer
283
258
  } finally {
284
259
  g.restore();
@@ -1,8 +1,5 @@
1
- import * as grok from 'datagrok-api/grok';
2
- import * as ui from 'datagrok-api/ui';
3
- import * as DG from 'datagrok-api/dg';
4
-
5
- import {GAP_SYMBOL, INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
1
+ import {GAP_SYMBOL, INotationProvider, ISeqSplitted, SeqSplittedBase, SplitterFunc}
2
+ from '@datagrok-libraries/bio/src/utils/macromolecule/types';
6
3
  import {getSplitterWithSeparator, StringListSeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
7
4
  import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
8
5
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
@@ -33,9 +30,8 @@ export class CyclizedSeqSplitted extends StringListSeqSplitted {
33
30
  if (!this._canonicals) {
34
31
  const len = this.length;
35
32
  this._canonicals = new Array<string>(len);
36
- for (let posIdx = 0; posIdx < len; ++posIdx) {
33
+ for (let posIdx = 0; posIdx < len; ++posIdx)
37
34
  this._canonicals[posIdx] = this.getCanonical(posIdx);
38
- }
39
35
  }
40
36
  return this._canonicals;
41
37
  }