@datagrok/bio 2.11.30 → 2.11.33
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/CHANGELOG.md +13 -0
- package/dist/36.js +1 -1
- package/dist/36.js.map +1 -1
- package/dist/42.js +1 -1
- package/dist/42.js.map +1 -1
- package/dist/590.js +2 -0
- package/dist/590.js.map +1 -0
- package/dist/709.js +1 -2
- package/dist/709.js.map +1 -1
- package/dist/79.js.map +1 -1
- package/dist/895.js +3 -0
- package/dist/895.js.map +1 -0
- package/dist/package-test.js +8 -1
- package/dist/package-test.js.LICENSE.txt +1 -0
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +8 -1
- package/dist/package.js.LICENSE.txt +1 -0
- package/dist/package.js.map +1 -1
- package/files/{data → monomer-libraries}/HELMCoreLibrary.json +594 -594
- package/files/tests/libraries/HELMmonomerSchema.json +96 -0
- package/package.json +12 -10
- package/scripts/sequence_generator.md +48 -0
- package/scripts/sequence_generator.py +515 -256
- package/src/package-test.ts +4 -0
- package/src/package.ts +26 -24
- package/src/tests/WebLogo-layout-tests.ts +37 -0
- package/src/tests/WebLogo-positions-test.ts +5 -0
- package/src/tests/WebLogo-project-tests.ts +63 -0
- package/src/tests/activity-cliffs-tests.ts +3 -2
- package/src/tests/monomer-libraries-tests.ts +7 -4
- package/src/tests/scoring.ts +3 -2
- package/src/tests/substructure-filters-tests.ts +3 -2
- package/src/tests/to-atomic-level-tests.ts +3 -2
- package/src/utils/helm-to-molfile.ts +3 -3
- package/src/utils/monomer-lib/lib-manager.ts +116 -0
- package/src/utils/monomer-lib/library-file-manager/consts.ts +1 -0
- package/src/utils/monomer-lib/library-file-manager/custom-monomer-lib-handlers.ts +80 -0
- package/src/utils/monomer-lib/library-file-manager/event-manager.ts +58 -0
- package/src/utils/monomer-lib/library-file-manager/file-manager.ts +187 -0
- package/src/utils/monomer-lib/library-file-manager/file-validator.ts +56 -0
- package/src/utils/monomer-lib/library-file-manager/style.css +8 -0
- package/src/utils/monomer-lib/library-file-manager/ui.ts +224 -0
- package/src/utils/monomer-lib/monomer-lib.ts +114 -0
- package/src/utils/poly-tool/const.ts +28 -0
- package/src/utils/poly-tool/monomer-lib-handler.ts +115 -0
- package/src/utils/poly-tool/types.ts +6 -0
- package/src/utils/poly-tool/ui.ts +2 -2
- package/src/viewers/vd-regions-viewer.ts +5 -4
- package/src/viewers/web-logo-viewer.ts +6 -5
- package/src/widgets/bio-substructure-filter.ts +4 -1
- package/files/libraries/HELMCoreLibrary.json +0 -18218
- package/src/utils/monomer-lib.ts +0 -305
- /package/dist/{709.js.LICENSE.txt → 895.js.LICENSE.txt} +0 -0
package/src/package-test.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as ui from 'datagrok-api/ui';
|
|
1
3
|
import * as DG from 'datagrok-api/dg';
|
|
2
4
|
|
|
3
5
|
import {runTests, TestContext, tests} from '@datagrok-libraries/utils/src/test';
|
|
@@ -17,6 +19,8 @@ import './tests/fasta-handler-test';
|
|
|
17
19
|
import './tests/fasta-export-tests';
|
|
18
20
|
import './tests/bio-tests';
|
|
19
21
|
import './tests/WebLogo-positions-test';
|
|
22
|
+
import './tests/WebLogo-project-tests';
|
|
23
|
+
import './tests/WebLogo-layout-tests';
|
|
20
24
|
import './tests/checkInputColumn-tests';
|
|
21
25
|
import './tests/similarity-diversity-tests';
|
|
22
26
|
import './tests/substructure-filters-tests';
|
package/src/package.ts
CHANGED
|
@@ -41,10 +41,8 @@ import {getMacromoleculeColumnPropertyPanel} from './widgets/representations';
|
|
|
41
41
|
import {saveAsFastaUI} from './utils/save-as-fasta';
|
|
42
42
|
import {BioSubstructureFilter} from './widgets/bio-substructure-filter';
|
|
43
43
|
import {WebLogoViewer} from './viewers/web-logo-viewer';
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
getLibraryPanelUI
|
|
47
|
-
} from './utils/monomer-lib';
|
|
44
|
+
import {MonomerLibManager} from './utils/monomer-lib/lib-manager';
|
|
45
|
+
import {getMonomerLibraryManagerLink, showManageLibrariesDialog} from './utils/monomer-lib/library-file-manager/ui';
|
|
48
46
|
import {demoBio01UI} from './demo/bio01-similarity-diversity';
|
|
49
47
|
import {demoBio01aUI} from './demo/bio01a-hierarchical-clustering-and-sequence-space';
|
|
50
48
|
import {demoBio01bUI} from './demo/bio01b-hierarchical-clustering-and-activity-cliffs';
|
|
@@ -88,7 +86,7 @@ export const _package = new BioPackage();
|
|
|
88
86
|
//description:
|
|
89
87
|
//output: object result
|
|
90
88
|
export function getMonomerLibHelper(): IMonomerLibHelper {
|
|
91
|
-
return
|
|
89
|
+
return MonomerLibManager.instance;
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
export let hydrophobPalette: SeqPaletteCustom | null = null;
|
|
@@ -110,7 +108,7 @@ export async function initBio() {
|
|
|
110
108
|
_package.logger.debug('Bio: initBio(), started');
|
|
111
109
|
const module = await grok.functions.call('Chem:getRdKitModule');
|
|
112
110
|
await Promise.all([
|
|
113
|
-
(async () => { await
|
|
111
|
+
(async () => { await MonomerLibManager.instance.loadLibraries(); })(),
|
|
114
112
|
(async () => {
|
|
115
113
|
const pkgProps = await _package.getProperties();
|
|
116
114
|
const bioPkgProps = new BioPackageProperties(pkgProps);
|
|
@@ -120,7 +118,7 @@ export async function initBio() {
|
|
|
120
118
|
_package.completeInit();
|
|
121
119
|
});
|
|
122
120
|
|
|
123
|
-
const monomerLib =
|
|
121
|
+
const monomerLib = MonomerLibManager.instance.getBioLib();
|
|
124
122
|
const monomers: string[] = [];
|
|
125
123
|
const logPs: number[] = [];
|
|
126
124
|
|
|
@@ -163,12 +161,19 @@ export function sequenceTooltip(col: DG.Column): DG.Widget<any> {
|
|
|
163
161
|
//name: getBioLib
|
|
164
162
|
//output: object monomerLib
|
|
165
163
|
export function getBioLib(): IMonomerLib {
|
|
166
|
-
return
|
|
164
|
+
return MonomerLibManager.instance.getBioLib();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//name: getUnitsHandler
|
|
168
|
+
//input: column sequence { semType: Macromolecule }
|
|
169
|
+
//output: object result
|
|
170
|
+
export function getUnitsHandler(sequence: DG.Column<string>): UnitsHandler {
|
|
171
|
+
return UnitsHandler.getOrCreate(sequence);
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
// -- Panels --
|
|
170
175
|
|
|
171
|
-
//name: Get Region
|
|
176
|
+
//name: Bioinformatics | Get Region
|
|
172
177
|
//description: Creates a new column with sequences of the region between start and end
|
|
173
178
|
//tags: panel
|
|
174
179
|
//input: column seqCol {semType: Macromolecule}
|
|
@@ -183,13 +188,14 @@ export function getRegionPanel(seqCol: DG.Column<string>): DG.Widget {
|
|
|
183
188
|
return funcEditor.widget();
|
|
184
189
|
}
|
|
185
190
|
|
|
186
|
-
//name: Manage Libraries
|
|
191
|
+
//name: Bioinformatics | Manage Monomer Libraries
|
|
187
192
|
//description:
|
|
188
193
|
//tags: panel, exclude-actions-panel
|
|
189
194
|
//input: column seqColumn {semType: Macromolecule}
|
|
190
195
|
//output: widget result
|
|
191
196
|
export async function libraryPanel(_seqColumn: DG.Column): Promise<DG.Widget> {
|
|
192
|
-
return getLibraryPanelUI();
|
|
197
|
+
// return getLibraryPanelUI();
|
|
198
|
+
return getMonomerLibraryManagerLink();
|
|
193
199
|
}
|
|
194
200
|
|
|
195
201
|
// -- Func Editors --
|
|
@@ -293,7 +299,7 @@ export function fastaSequenceCellRenderer(): MacromoleculeSequenceCellRenderer {
|
|
|
293
299
|
|
|
294
300
|
// -- Property panels --
|
|
295
301
|
|
|
296
|
-
//name: Sequence Renderer
|
|
302
|
+
//name: Bioinformatics | Sequence Renderer
|
|
297
303
|
//input: column molColumn {semType: Macromolecule}
|
|
298
304
|
//tags: panel
|
|
299
305
|
//output: widget result
|
|
@@ -650,18 +656,6 @@ export async function compositionAnalysis(): Promise<void> {
|
|
|
650
656
|
await handler(col);
|
|
651
657
|
}
|
|
652
658
|
|
|
653
|
-
// 2023-05-17 Representations does not work at BioIT
|
|
654
|
-
// //name: Representations
|
|
655
|
-
// //tags: panel, widgets
|
|
656
|
-
// //input: cell macroMolecule {semType: Macromolecule}
|
|
657
|
-
// //output: widget result
|
|
658
|
-
// export async function peptideMolecule(macroMolecule: DG.Cell): Promise<DG.Widget> {
|
|
659
|
-
// const monomersLibFile = await _package.files.readAsText(HELM_CORE_LIB_FILENAME);
|
|
660
|
-
// const monomersLibObject: any[] = JSON.parse(monomersLibFile);
|
|
661
|
-
//
|
|
662
|
-
// return representationsWidget(macroMolecule, monomersLibObject);
|
|
663
|
-
// }
|
|
664
|
-
|
|
665
659
|
//name: importFasta
|
|
666
660
|
//description: Opens FASTA file
|
|
667
661
|
//tags: file-handler
|
|
@@ -871,6 +865,14 @@ export async function sequenceSimilarityScoring(
|
|
|
871
865
|
return scores;
|
|
872
866
|
}
|
|
873
867
|
|
|
868
|
+
|
|
869
|
+
//top-menu: Bio | Manage | Monomer Libraries
|
|
870
|
+
//name: Manage Monomer Libraries
|
|
871
|
+
//description: Manage HELM monomer libraries
|
|
872
|
+
export async function manageMonomerLibraries(): Promise<void> {
|
|
873
|
+
showManageLibrariesDialog();
|
|
874
|
+
}
|
|
875
|
+
|
|
874
876
|
//name: saveAsFasta
|
|
875
877
|
//description: As FASTA...
|
|
876
878
|
//tags: fileExporter
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
4
|
+
|
|
5
|
+
import wu from 'wu';
|
|
6
|
+
|
|
7
|
+
import {category, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
|
|
8
|
+
|
|
9
|
+
import {awaitGrid} from './utils';
|
|
10
|
+
import {WebLogoViewer} from '../viewers/web-logo-viewer';
|
|
11
|
+
|
|
12
|
+
import {_package} from '../package-test';
|
|
13
|
+
|
|
14
|
+
category('WebLogo-layout', () => {
|
|
15
|
+
test('fasta', async () => {
|
|
16
|
+
const df = await _package.files.readCsv('tests/filter_FASTA.csv');
|
|
17
|
+
const col = df.getCol('fasta');
|
|
18
|
+
await grok.data.detectSemanticTypes(df);
|
|
19
|
+
const view = grok.shell.addTableView(df);
|
|
20
|
+
const wlViewer = await df.plot.fromType('WebLogo',
|
|
21
|
+
{sequenceColumnName: col.name}) as unknown as WebLogoViewer;
|
|
22
|
+
view.dockManager.dock(wlViewer);
|
|
23
|
+
await wlViewer.awaitRendered();
|
|
24
|
+
await awaitGrid(view.grid);
|
|
25
|
+
|
|
26
|
+
const viewLayout = view.saveLayout();
|
|
27
|
+
const viewLayoutJsonStr = viewLayout.toJson();
|
|
28
|
+
view.loadLayout(viewLayout);
|
|
29
|
+
await wlViewer.awaitRendered();
|
|
30
|
+
await awaitGrid(view.grid);
|
|
31
|
+
|
|
32
|
+
const viewersA = wu(view.viewers).toArray();
|
|
33
|
+
expect(viewersA.length, 2 /* Grid and WebLogo */);
|
|
34
|
+
expect(viewersA.filter((f) => f.type === 'Grid').length, 1);
|
|
35
|
+
expect(viewersA.filter((f) => f.type === 'WebLogo').length, 1);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -57,6 +57,7 @@ ATC-G-TTGC--
|
|
|
57
57
|
for (const m of positions[i].getMonomers())
|
|
58
58
|
expect(positions[i].getFreq(m).rowCount, resAllDf1[i].getFreq(m).rowCount);
|
|
59
59
|
}
|
|
60
|
+
await wlViewer.awaitRendered();
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
test('positions with shrinkEmptyTail option true (filtered)', async () => {
|
|
@@ -106,6 +107,7 @@ ATC-G-TTGC--
|
|
|
106
107
|
for (const m of positions[i].getMonomers())
|
|
107
108
|
expect(positions[i].getFreq(m).rowCount, resAllDf1[i].getFreq(m).rowCount);
|
|
108
109
|
}
|
|
110
|
+
await wlViewer.awaitRendered();
|
|
109
111
|
});
|
|
110
112
|
|
|
111
113
|
test('positions with skipEmptyPositions option', async () => {
|
|
@@ -143,6 +145,7 @@ ATC-G-TTGC--
|
|
|
143
145
|
const tgtPos = tgtPosList[posI];
|
|
144
146
|
expectPositionInfo(resPos, tgtPos);
|
|
145
147
|
}
|
|
148
|
+
await wlViewer.awaitRendered();
|
|
146
149
|
});
|
|
147
150
|
|
|
148
151
|
test('count sequences for monomer at position', async () => {
|
|
@@ -178,6 +181,7 @@ ATC-G-TTGC--
|
|
|
178
181
|
const uh = UnitsHandler.getOrCreate(seqCol);
|
|
179
182
|
const countAt1 = countForMonomerAtPosition(df, uh, df.filter, 'G', atPI1);
|
|
180
183
|
expect(countAt1, 5);
|
|
184
|
+
await wlViewer.awaitRendered();
|
|
181
185
|
});
|
|
182
186
|
|
|
183
187
|
test('empty', async () => {
|
|
@@ -196,6 +200,7 @@ ATC-G-TTGC--
|
|
|
196
200
|
tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN);
|
|
197
201
|
}, 500);
|
|
198
202
|
const resPosList: PI[] = wlViewer['positions'];
|
|
203
|
+
await wlViewer.awaitRendered();
|
|
199
204
|
});
|
|
200
205
|
});
|
|
201
206
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
4
|
+
|
|
5
|
+
import wu from 'wu';
|
|
6
|
+
|
|
7
|
+
import {category, delay, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
|
|
8
|
+
|
|
9
|
+
import {awaitGrid} from './utils';
|
|
10
|
+
import {WebLogoViewer} from '../viewers/web-logo-viewer';
|
|
11
|
+
|
|
12
|
+
import {_package} from '../package-test';
|
|
13
|
+
|
|
14
|
+
const PROJECT_PREFIX: string = 'Tests.Bio.WebLogo-project';
|
|
15
|
+
|
|
16
|
+
category('WebLogo-project', () => {
|
|
17
|
+
test('fasta', async () => {
|
|
18
|
+
const prjName = `${PROJECT_PREFIX}.fasta`;
|
|
19
|
+
const df = await _package.files.readCsv('tests/filter_FASTA.csv');
|
|
20
|
+
const tableName = df.name;
|
|
21
|
+
const col = df.getCol('fasta');
|
|
22
|
+
await grok.data.detectSemanticTypes(df);
|
|
23
|
+
const view = grok.shell.addTableView(df);
|
|
24
|
+
const wlViewer = await df.plot.fromType('WebLogo',
|
|
25
|
+
{sequenceColumnName: col.name}) as unknown as WebLogoViewer;
|
|
26
|
+
view.dockManager.dock(wlViewer);
|
|
27
|
+
await wlViewer.awaitRendered();
|
|
28
|
+
await awaitGrid(view.grid);
|
|
29
|
+
|
|
30
|
+
await uploadProject(prjName, df.getTableInfo(), view, df);
|
|
31
|
+
grok.shell.closeAll();
|
|
32
|
+
await delay(500);
|
|
33
|
+
|
|
34
|
+
const prj2 = await grok.dapi.projects.open(prjName);
|
|
35
|
+
const view2 = grok.shell.getTableView(tableName);
|
|
36
|
+
|
|
37
|
+
const viewersA = wu(view2.viewers).toArray();
|
|
38
|
+
expect(viewersA.length, 2);
|
|
39
|
+
expect(viewersA.filter((f) => f.type === 'Grid').length, 1);
|
|
40
|
+
const wlViewer2 = viewersA.find((f) => f.type === 'WebLogo') as WebLogoViewer;
|
|
41
|
+
expect(!!wlViewer2, true);
|
|
42
|
+
|
|
43
|
+
await awaitGrid(view.grid);
|
|
44
|
+
await wlViewer2.awaitRendered();
|
|
45
|
+
// TODO: Check WebLogo viewer content
|
|
46
|
+
}, {skipReason: 'depends on 1.18'});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export async function uploadProject(projectName: string, tableInfo: DG.TableInfo,
|
|
50
|
+
view: DG.TableView, df: DG.DataFrame): Promise<void> {
|
|
51
|
+
const project = DG.Project.create();
|
|
52
|
+
const viewLayout = view.saveLayout();
|
|
53
|
+
|
|
54
|
+
await grok.dapi.layouts.save(view.saveLayout());
|
|
55
|
+
await grok.dapi.tables.uploadDataFrame(df);
|
|
56
|
+
await grok.dapi.tables.save(tableInfo);
|
|
57
|
+
|
|
58
|
+
project.name = projectName;
|
|
59
|
+
project.addChild(tableInfo);
|
|
60
|
+
project.addChild(viewLayout); // cause error
|
|
61
|
+
|
|
62
|
+
await grok.dapi.projects.save(project);
|
|
63
|
+
}
|
|
@@ -10,8 +10,9 @@ import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule
|
|
|
10
10
|
import {BitArrayMetricsNames} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
11
11
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
12
12
|
import {
|
|
13
|
-
getUserLibSettings,
|
|
13
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
14
14
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
15
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
15
16
|
|
|
16
17
|
import {_package} from '../package-test';
|
|
17
18
|
import {DimReductionMethods} from '@datagrok-libraries/ml/src/multi-column-dimensionality-reduction/types';
|
|
@@ -23,7 +24,7 @@ category('activityCliffs', async () => {
|
|
|
23
24
|
|
|
24
25
|
let monomerLibHelper: IMonomerLibHelper;
|
|
25
26
|
/** Backup actual user's monomer libraries settings */
|
|
26
|
-
let userLibSettings:
|
|
27
|
+
let userLibSettings: UserLibSettings;
|
|
27
28
|
const seqEncodingFunc = DG.Func.find({name: 'macromoleculePreprocessingFunction', package: 'Bio'})[0];
|
|
28
29
|
const helmEncodingFunc = DG.Func.find({name: 'helmPreprocessingFunction', package: 'Bio'})[0];
|
|
29
30
|
before(async () => {
|
|
@@ -6,9 +6,10 @@ import {test, after, before, category, expect} from '@datagrok-libraries/utils/s
|
|
|
6
6
|
|
|
7
7
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
8
8
|
import {
|
|
9
|
-
getUserLibSettings,
|
|
9
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
10
10
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
11
|
-
import {
|
|
11
|
+
import {MonomerLibFileManager} from '../utils/monomer-lib/library-file-manager/file-manager';
|
|
12
|
+
import {MonomerLibFileEventManager} from '../utils/monomer-lib/library-file-manager/event-manager';
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
category('monomerLibraries', () => {
|
|
@@ -50,7 +51,9 @@ category('monomerLibraries', () => {
|
|
|
50
51
|
test('empty', async () => {
|
|
51
52
|
// exclude all monomer libraries for empty set
|
|
52
53
|
const libSettings = await getUserLibSettings();
|
|
53
|
-
const
|
|
54
|
+
const libFileEventManager = MonomerLibFileEventManager.getInstance();
|
|
55
|
+
const libFileManager = await MonomerLibFileManager.getInstance(libFileEventManager);
|
|
56
|
+
const libFnList = libFileManager.getValidLibraryPaths();
|
|
54
57
|
libSettings.exclude = libFnList;
|
|
55
58
|
libSettings.explicit = [];
|
|
56
59
|
await setUserLibSettings(libSettings);
|
|
@@ -59,5 +62,5 @@ category('monomerLibraries', () => {
|
|
|
59
62
|
const currentMonomerLib = monomerLibHelper.getBioLib();
|
|
60
63
|
expect(currentMonomerLib.getPolymerTypes().length === 0, true);
|
|
61
64
|
const monomerOfTypesList = currentMonomerLib.getMonomerMolsByPolymerType('PEPTIDE');
|
|
62
|
-
});
|
|
65
|
+
}, {skipReason: '#2690'});
|
|
63
66
|
});
|
package/src/tests/scoring.ts
CHANGED
|
@@ -8,8 +8,9 @@ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/sr
|
|
|
8
8
|
|
|
9
9
|
import {sequenceIdentityScoring, sequenceSimilarityScoring} from '../package';
|
|
10
10
|
import {
|
|
11
|
-
|
|
11
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
12
12
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
13
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
13
14
|
|
|
14
15
|
category('Scoring', () => {
|
|
15
16
|
const sequence = 'sequence';
|
|
@@ -29,7 +30,7 @@ PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[
|
|
|
29
30
|
|
|
30
31
|
let monomerLibHelper: IMonomerLibHelper;
|
|
31
32
|
/** Backup actual user's monomer libraries settings */
|
|
32
|
-
let userLibSettings:
|
|
33
|
+
let userLibSettings: UserLibSettings;
|
|
33
34
|
|
|
34
35
|
before(async () => {
|
|
35
36
|
monomerLibHelper = await getMonomerLibHelper();
|
|
@@ -5,8 +5,9 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
import {after, before, category, test, expect, delay, testEvent, awaitCheck} from '@datagrok-libraries/utils/src/test';
|
|
6
6
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
9
9
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
10
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
10
11
|
|
|
11
12
|
import {awaitGrid, readDataframe} from './utils';
|
|
12
13
|
import {
|
|
@@ -21,7 +22,7 @@ import {_package} from '../package-test';
|
|
|
21
22
|
category('substructureFilters', async () => {
|
|
22
23
|
let monomerLibHelper: IMonomerLibHelper;
|
|
23
24
|
/** Backup actual user's monomer libraries settings */
|
|
24
|
-
let userLibSettings:
|
|
25
|
+
let userLibSettings: UserLibSettings;
|
|
25
26
|
|
|
26
27
|
before(async () => {
|
|
27
28
|
monomerLibHelper = await getMonomerLibHelper();
|
|
@@ -11,8 +11,9 @@ import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
|
|
|
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 {
|
|
14
|
-
getUserLibSettings,
|
|
14
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
15
15
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
16
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
16
17
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
17
18
|
|
|
18
19
|
import {toAtomicLevel} from '../package';
|
|
@@ -56,7 +57,7 @@ category('toAtomicLevel', async () => {
|
|
|
56
57
|
|
|
57
58
|
let monomerLibHelper: IMonomerLibHelper;
|
|
58
59
|
/** Backup actual user's monomer libraries settings */
|
|
59
|
-
let userLibSettings:
|
|
60
|
+
let userLibSettings: UserLibSettings;
|
|
60
61
|
|
|
61
62
|
before(async () => {
|
|
62
63
|
monomerLibHelper = await getMonomerLibHelper();
|
|
@@ -5,11 +5,11 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
|
|
6
6
|
import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
|
|
7
7
|
import {MolfileHandlerBase} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler-base';
|
|
8
|
-
import {
|
|
8
|
+
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
9
9
|
import {HELM_POLYMER_TYPE, HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
|
|
10
10
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {MonomerLibManager} from './monomer-lib/lib-manager';
|
|
13
13
|
|
|
14
14
|
import {_package} from '../package';
|
|
15
15
|
|
|
@@ -173,7 +173,7 @@ class MonomerWrapper {
|
|
|
173
173
|
monomerSymbol: string,
|
|
174
174
|
polymerType: HELM_POLYMER_TYPE,
|
|
175
175
|
) {
|
|
176
|
-
const monomerLib =
|
|
176
|
+
const monomerLib = MonomerLibManager.instance.getBioLib();
|
|
177
177
|
const monomer = monomerLib.getMonomer(polymerType, monomerSymbol);
|
|
178
178
|
if (!monomer)
|
|
179
179
|
throw new Error(`Monomer ${monomerSymbol} is not found in the library`);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
4
|
+
import * as DG from 'datagrok-api/dg';
|
|
5
|
+
|
|
6
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
|
|
7
|
+
import {
|
|
8
|
+
getUserLibSettings, setUserLibSettings, LIB_PATH
|
|
9
|
+
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
10
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
11
|
+
import {
|
|
12
|
+
IMonomerLibHelper,
|
|
13
|
+
} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
14
|
+
import {MonomerLib} from './monomer-lib';
|
|
15
|
+
import {MonomerLibFileManager} from './library-file-manager/file-manager';
|
|
16
|
+
import {MonomerLibFileEventManager} from './library-file-manager/event-manager';
|
|
17
|
+
import {_package} from '../../package';
|
|
18
|
+
|
|
19
|
+
type MonomerLibWindowType = Window & { $monomerLibHelper: MonomerLibManager };
|
|
20
|
+
declare const window: MonomerLibWindowType;
|
|
21
|
+
|
|
22
|
+
export async function getLibFileNameList(): Promise<string[]> {
|
|
23
|
+
const fileEventManager = MonomerLibFileEventManager.getInstance();
|
|
24
|
+
const fileManager = await MonomerLibFileManager.getInstance(fileEventManager);
|
|
25
|
+
return fileManager.getValidLibraryPaths();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Singleton wrapper for MonomerLib, provides API for managing libraries on
|
|
29
|
+
* the platform */
|
|
30
|
+
export class MonomerLibManager implements IMonomerLibHelper {
|
|
31
|
+
private readonly _monomerLib = new MonomerLib({});
|
|
32
|
+
|
|
33
|
+
/** Protect constructor to prevent multiple instantiation. */
|
|
34
|
+
protected constructor() {}
|
|
35
|
+
|
|
36
|
+
/** Singleton monomer library
|
|
37
|
+
* @return {MonomerLibManager} MonomerLibHelper instance
|
|
38
|
+
*/
|
|
39
|
+
getBioLib(): IMonomerLib {
|
|
40
|
+
return this._monomerLib;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Allows syncing with managing settings/loading libraries */
|
|
44
|
+
public loadLibrariesPromise: Promise<void> = Promise.resolve();
|
|
45
|
+
|
|
46
|
+
/** Loads libraries based on settings in user storage {@link LIB_STORAGE_NAME}
|
|
47
|
+
* @param {boolean} reload Clean {@link monomerLib} before load libraries [false]
|
|
48
|
+
*/
|
|
49
|
+
async loadLibraries(reload: boolean = false): Promise<void> {
|
|
50
|
+
return this.loadLibrariesPromise = this.loadLibrariesPromise.then(async () => {
|
|
51
|
+
// WARNING: This function is not allowed to throw any exception,
|
|
52
|
+
// because it will prevent further handling monomer library settings
|
|
53
|
+
// through blocking this.loadLibrariesPromise
|
|
54
|
+
try {
|
|
55
|
+
const [libFileNameList, settings]: [string[], UserLibSettings] = await Promise.all([
|
|
56
|
+
getLibFileNameList(),
|
|
57
|
+
getUserLibSettings(),
|
|
58
|
+
]);
|
|
59
|
+
const filteredLibFnList = libFileNameList
|
|
60
|
+
.filter((libFileName) => !settings.exclude.includes(libFileName))
|
|
61
|
+
.filter((libFileName) => settings.explicit.length > 0 ? settings.explicit.includes(libFileName) : true);
|
|
62
|
+
const libs: IMonomerLib[] = await Promise.all(filteredLibFnList
|
|
63
|
+
.map((libFileName) => {
|
|
64
|
+
//TODO handle whether files are in place
|
|
65
|
+
return this.readLibrary(LIB_PATH, libFileName).catch((err: any) => {
|
|
66
|
+
const errMsg: string = `Loading monomers from '${libFileName}' error: ` +
|
|
67
|
+
`${err instanceof Error ? err.message : err.toString()}`;
|
|
68
|
+
return new MonomerLib({}, errMsg);
|
|
69
|
+
});
|
|
70
|
+
}));
|
|
71
|
+
this._monomerLib.updateLibs(libs, reload);
|
|
72
|
+
} catch (err: any) {
|
|
73
|
+
const errMsg: string = 'Loading monomer libraries error: ' +
|
|
74
|
+
`${err instanceof Error ? err.message : err.toString()}`;
|
|
75
|
+
grok.shell.warning(errMsg);
|
|
76
|
+
|
|
77
|
+
const errStack = err instanceof Error ? err.stack : undefined;
|
|
78
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Reads library from file shares, handles .json and .sdf
|
|
84
|
+
* @param {string} path Path to library file
|
|
85
|
+
* @param {string} fileName Name of library file
|
|
86
|
+
* @return {Promise<IMonomerLib>} Promise of IMonomerLib
|
|
87
|
+
*/
|
|
88
|
+
async readLibrary(path: string, fileName: string): Promise<IMonomerLib> {
|
|
89
|
+
const eventManager = MonomerLibFileEventManager.getInstance();
|
|
90
|
+
const libFileManager = await MonomerLibFileManager.getInstance(eventManager);
|
|
91
|
+
const lib: IMonomerLib = await libFileManager.loadLibraryFromFile(path, fileName);
|
|
92
|
+
return lib;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Reset user settings to the specified library. WARNING: clears user * settings */
|
|
96
|
+
public async selectSpecifiedLibraries(libFileNameList: string[]): Promise<void> {
|
|
97
|
+
const invalidNames = await this.getInvalidFileNames(libFileNameList);
|
|
98
|
+
if (invalidNames.length > 0)
|
|
99
|
+
throw new Error(`Cannot select libraries ${invalidNames}: no such library in the list`);
|
|
100
|
+
const settings = await getUserLibSettings();
|
|
101
|
+
settings.exclude = (await getLibFileNameList()).filter((fileName) => !libFileNameList.includes(fileName));
|
|
102
|
+
await setUserLibSettings(settings);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private async getInvalidFileNames(libFileNameList: string[]): Promise<string[]> {
|
|
106
|
+
const availableFileNames = await getLibFileNameList();
|
|
107
|
+
const invalidNames = libFileNameList.filter((fileName) => !availableFileNames.includes(fileName));
|
|
108
|
+
return invalidNames;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// -- Instance singleton --
|
|
112
|
+
public static get instance(): MonomerLibManager {
|
|
113
|
+
if (!window.$monomerLibHelper) window.$monomerLibHelper = new MonomerLibManager();
|
|
114
|
+
return window.$monomerLibHelper;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HELM_JSON_SCHEMA_PATH = 'System:AppData/Bio/tests/libraries/HELMmonomerSchema.json';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Do not change these import lines to match external modules in webpack configuration */
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
4
|
+
import * as DG from 'datagrok-api/dg';
|
|
5
|
+
|
|
6
|
+
import {createJsonMonomerLibFromSdf} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
7
|
+
import {PolyToolMonomerLibHandler} from '../../poly-tool/monomer-lib-handler';
|
|
8
|
+
|
|
9
|
+
interface CustomMonomerLibHandler {
|
|
10
|
+
getHelmLibContent(): Promise<string>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Casts specific SDF files as HELM-standard monomer libraries */
|
|
14
|
+
export class SdfMonomerLibHandler implements CustomMonomerLibHandler {
|
|
15
|
+
constructor(private fileName: string, private fileContent: string) {
|
|
16
|
+
this.validateChemInstallation();
|
|
17
|
+
this.validate();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async getHelmLibContent(): Promise<string> {
|
|
21
|
+
const bytes = this.transformToBytes();
|
|
22
|
+
const dfSdf = await grok.functions.call('Chem:importSdf', {bytes});
|
|
23
|
+
const jsonContent = createJsonMonomerLibFromSdf(dfSdf[0]);
|
|
24
|
+
return JSON.stringify(jsonContent);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private transformToBytes(): Uint8Array {
|
|
28
|
+
return new TextEncoder().encode(this.fileContent);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private validateChemInstallation(): void {
|
|
32
|
+
const funcList: DG.Func[] = DG.Func.find({package: 'Chem', name: 'importSdf'});
|
|
33
|
+
if (funcList.length === 1)
|
|
34
|
+
return;
|
|
35
|
+
throw new Error('MonomerLibFileManager: Chem package is not installed, cannot convert SDF to JSON');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private validate(): void {
|
|
39
|
+
if (!this.fileName.endsWith('.sdf'))
|
|
40
|
+
throw new Error(`File ${this.fileName} is not an SDF file`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
/** Handler of custom monomer libs for PolyTool */
|
|
46
|
+
export class PolyToolCsvLibHandler implements CustomMonomerLibHandler {
|
|
47
|
+
constructor(private fileName: string, private fileContent: string) {
|
|
48
|
+
this.validateFileType();
|
|
49
|
+
const df = DG.DataFrame.fromCsv(this.fileContent);
|
|
50
|
+
const json = this.toJson(df);
|
|
51
|
+
this.polyToolMonomerLib = new PolyToolMonomerLibHandler(json);
|
|
52
|
+
this.validateContent();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private polyToolMonomerLib: PolyToolMonomerLibHandler;
|
|
56
|
+
|
|
57
|
+
async getHelmLibContent(): Promise<string> {
|
|
58
|
+
const rawLibData = this.polyToolMonomerLib.getJsonMonomerLib();
|
|
59
|
+
return JSON.stringify(rawLibData);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private toJson(df: DG.DataFrame): any[] {
|
|
63
|
+
return Array.from({length: df.rowCount}, (_, idx) =>
|
|
64
|
+
df.columns.names().reduce((entry: { [key: string]: any }, colName) => {
|
|
65
|
+
entry[colName] = df.get(colName, idx);
|
|
66
|
+
return entry;
|
|
67
|
+
}, {})
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private validateFileType(): void {
|
|
72
|
+
if (!this.fileName.endsWith('.csv'))
|
|
73
|
+
throw new Error(`File ${this.fileName} is not an CSV file`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private validateContent(): void {
|
|
77
|
+
if (!this.polyToolMonomerLib.isValid())
|
|
78
|
+
throw new Error('Invalid format of CSV monomer lib');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as rxjs from 'rxjs';
|
|
2
|
+
import {debounceTime, tap} from 'rxjs/operators';
|
|
3
|
+
|
|
4
|
+
export class MonomerLibFileEventManager {
|
|
5
|
+
// WARNING: this must be a singleton because it manages the unique state
|
|
6
|
+
private constructor() {}
|
|
7
|
+
|
|
8
|
+
private static _instance: MonomerLibFileEventManager;
|
|
9
|
+
|
|
10
|
+
static getInstance(): MonomerLibFileEventManager {
|
|
11
|
+
if (!MonomerLibFileEventManager._instance)
|
|
12
|
+
MonomerLibFileEventManager._instance = new MonomerLibFileEventManager();
|
|
13
|
+
|
|
14
|
+
return MonomerLibFileEventManager._instance;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private _libraryFilesUpdateSubject$ = new rxjs.BehaviorSubject<string[]>([]);
|
|
18
|
+
private _addLibraryFilesSubject$ = new rxjs.Subject<void>();
|
|
19
|
+
private _librarySelectionSubject$ = new rxjs.Subject<[string, boolean]>();
|
|
20
|
+
|
|
21
|
+
getValidFilesPathList(): string[] {
|
|
22
|
+
return this._libraryFilesUpdateSubject$.getValue();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
changeValidFilesPathList(newList: string[]): void {
|
|
26
|
+
this._libraryFilesUpdateSubject$.next(newList);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get updateUIControlsRequested$(): rxjs.Observable<string[]> {
|
|
30
|
+
return this._libraryFilesUpdateSubject$.pipe(
|
|
31
|
+
// debounceTime(1000)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get updateValidLibraryFileListRequested$(): rxjs.Observable<string[]> {
|
|
36
|
+
return this._libraryFilesUpdateSubject$.pipe(
|
|
37
|
+
// debounceTime(3000)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get addLibraryFileRequested$(): rxjs.Observable<void> {
|
|
42
|
+
return this._addLibraryFilesSubject$.pipe(
|
|
43
|
+
// debounceTime(1000)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
addLibraryFile(): void {
|
|
48
|
+
this._addLibraryFilesSubject$.next();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get librarySelectionRequested$(): rxjs.Observable<[string, boolean]> {
|
|
52
|
+
return this._librarySelectionSubject$;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
updateLibrarySelectionStatus(fileName: string, isSelected: boolean): void {
|
|
56
|
+
this._librarySelectionSubject$.next([fileName, isSelected]);
|
|
57
|
+
}
|
|
58
|
+
}
|