@datagrok/bio 2.0.32 → 2.0.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/dist/package-test.js +218 -24
- package/dist/package.js +168 -1
- package/files/libraries/HELMCoreLibrary.json +18218 -0
- package/package.json +2 -2
- package/src/package.ts +201 -1
- package/src/tests/activity-cliffs-tests.ts +19 -4
- package/src/tests/similarity-diversity-tests.ts +35 -19
- package/test-Bio-3afbd4014fa1-15e7930e.html +389 -0
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.0.
|
|
8
|
+
"version": "2.0.33",
|
|
9
9
|
"description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"webpack-cli": "^4.6.0"
|
|
48
48
|
},
|
|
49
49
|
"grokDependencies": {
|
|
50
|
-
"@datagrok/chem": "1.3.
|
|
50
|
+
"@datagrok/chem": "1.3.19",
|
|
51
51
|
"@datagrok/helm": "latest"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
package/src/package.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {getMacroMol} from './utils/atomic-works';
|
|
|
19
19
|
import {MacromoleculeSequenceCellRenderer} from './utils/cell-renderer';
|
|
20
20
|
import {convert} from './utils/convert';
|
|
21
21
|
import {getMacroMolColumnPropertyPanel, representationsWidget} from './widgets/representations';
|
|
22
|
-
import {TAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
22
|
+
import {MonomerFreqs, TAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
23
23
|
import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule'
|
|
24
24
|
import {_toAtomicLevel} from '@datagrok-libraries/bio/src/utils/to-atomic-level';
|
|
25
25
|
import {FastaFileHandler} from '@datagrok-libraries/bio/src/utils/fasta-handler';
|
|
@@ -39,9 +39,209 @@ import {saveAsFastaUI} from './utils/save-as-fasta';
|
|
|
39
39
|
import {BioSubstructureFilter} from './widgets/bio-substructure-filter';
|
|
40
40
|
import { getMonomericMols } from './calculations/monomerLevelMols';
|
|
41
41
|
import { delay } from '@datagrok-libraries/utils/src/test';
|
|
42
|
+
import {Observable, Subject} from 'rxjs';
|
|
43
|
+
|
|
44
|
+
const STORAGE_NAME = 'Libraries';
|
|
45
|
+
const LIB_PATH = 'libraries/';
|
|
46
|
+
const expectedMonomerData = ['symbol', 'name', 'molfile', 'rgroups', 'polymerType', 'monomerType'];
|
|
47
|
+
|
|
48
|
+
let monomerLib: IMonomerLib | null = null;
|
|
49
|
+
export let hydrophobPalette: SeqPaletteCustom | null = null;
|
|
50
|
+
|
|
51
|
+
class MonomerLib implements IMonomerLib {
|
|
52
|
+
private _monomers: { [type: string]: { [name: string]: Monomer } } = {};
|
|
53
|
+
private _onChanged = new Subject<any>();
|
|
54
|
+
|
|
55
|
+
getMonomer(monomerType: string, monomerName: string): Monomer | null {
|
|
56
|
+
if (monomerType in this._monomers! && monomerName in this._monomers![monomerType])
|
|
57
|
+
return this._monomers![monomerType][monomerName];
|
|
58
|
+
else
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getTypes(): string[] {
|
|
63
|
+
return Object.keys(this._monomers);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getMonomersByType(type: string): {[symbol: string]: string} {
|
|
67
|
+
let res: {[symbol: string]: string} = {};
|
|
68
|
+
|
|
69
|
+
Object.keys(this._monomers[type]).forEach(monomerSymbol => {
|
|
70
|
+
res[monomerSymbol] = this._monomers[type][monomerSymbol].molfile;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return res;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get onChanged(): Observable<any> {
|
|
77
|
+
return this._onChanged;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public update(monomers: { [type: string]: { [name: string]: Monomer } }): void {
|
|
81
|
+
Object.keys(monomers).forEach(type => {
|
|
82
|
+
//could possibly rewrite -> TODO: check duplicated monomer symbol
|
|
83
|
+
|
|
84
|
+
if (!this.getTypes().includes(type))
|
|
85
|
+
this._monomers![type] = {};
|
|
86
|
+
|
|
87
|
+
Object.keys(monomers[type]).forEach(monomerName =>{
|
|
88
|
+
this._monomers[type][monomerName] = monomers[type][monomerName];
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
this._onChanged.next();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type Monomer = {
|
|
97
|
+
symbol: string,
|
|
98
|
+
name: string,
|
|
99
|
+
molfile: string,
|
|
100
|
+
rgroups: {capGroupSmiles: string, alternateId: string, capGroupName: string, label: string }[],
|
|
101
|
+
polymerType: string,
|
|
102
|
+
monomerType: string,
|
|
103
|
+
data: {[property: string]: string}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//expected types: HELM_AA, HELM_BASE, HELM_CHEM, HELM_LINKER, HELM_SUGAR
|
|
107
|
+
export interface IMonomerLib {
|
|
108
|
+
getMonomer(monomerType: string, monomerName: string): Monomer | null;
|
|
109
|
+
getMonomersByType(type: string): {[symbol: string]: string} | null;
|
|
110
|
+
getTypes(): string[];
|
|
111
|
+
update(monomers: { [type: string]: { [name: string]: Monomer } }): void;
|
|
112
|
+
get onChanged(): Observable<any>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class SeqPaletteCustom implements bio.SeqPalette {
|
|
116
|
+
private readonly _palette: { [m: string]: string };
|
|
117
|
+
constructor(palette: { [m: string]: string }) {
|
|
118
|
+
this._palette = palette;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public get(m: string): string {
|
|
122
|
+
return this._palette[m];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
42
125
|
|
|
43
126
|
//tags: init
|
|
44
127
|
export async function initBio() {
|
|
128
|
+
await loadLibraries();
|
|
129
|
+
let monomers: string[] = [];
|
|
130
|
+
let logPs: number[] = [];
|
|
131
|
+
const module = await grok.functions.call('Chem:getRdKitModule');
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
const series = monomerLib!.getMonomersByType('PEPTIDE')!;
|
|
135
|
+
Object.keys(series).forEach(symbol => {
|
|
136
|
+
monomers.push(symbol);
|
|
137
|
+
const block = series[symbol].replaceAll('#R', 'O ');
|
|
138
|
+
const mol = module.get_mol(block);
|
|
139
|
+
const logP = JSON.parse(mol.get_descriptors()).CrippenClogP;
|
|
140
|
+
logPs.push(logP);
|
|
141
|
+
mol?.delete();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const sum = logPs.reduce((a, b) => a + b, 0);
|
|
145
|
+
const avg = (sum / logPs.length) || 0;
|
|
146
|
+
|
|
147
|
+
let palette: {[monomer: string]: string} = {};
|
|
148
|
+
for (let i = 0; i < monomers.length; i++) {
|
|
149
|
+
palette[monomers[i]] = logPs[i] < avg ? '#4682B4' : '#DC143C';
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
hydrophobPalette = new SeqPaletteCustom(palette);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function loadLibraries() {
|
|
156
|
+
let uploadedLibraries: string[] = Object.values(await grok.dapi.userDataStorage.get(STORAGE_NAME, true));
|
|
157
|
+
for (let i = 0; i < 1; ++i)
|
|
158
|
+
await monomerManager(uploadedLibraries[i]);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//name: monomerManager
|
|
162
|
+
//input: string value
|
|
163
|
+
export async function monomerManager(value: string) {
|
|
164
|
+
let data: any[] = [];
|
|
165
|
+
let file;
|
|
166
|
+
let dfSdf;
|
|
167
|
+
if (value.endsWith('.sdf')) {
|
|
168
|
+
const funcList: DG.Func[] = DG.Func.find({package: 'Chem', name: 'importSdf'});
|
|
169
|
+
console.debug(`Helm: initHelm() funcList.length = ${funcList.length}`);
|
|
170
|
+
if (funcList.length === 1) {
|
|
171
|
+
file = await _package.files.readAsBytes(`${LIB_PATH}${value}`);
|
|
172
|
+
dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
|
|
173
|
+
data = createJsonMonomerLibFromSdf(dfSdf[0]);
|
|
174
|
+
} else {
|
|
175
|
+
grok.shell.warning('Chem package is not installed');
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
const file = await _package.files.readAsText(`${LIB_PATH}${value}`);
|
|
179
|
+
data = JSON.parse(file);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (monomerLib == null)
|
|
183
|
+
monomerLib = new MonomerLib();
|
|
184
|
+
|
|
185
|
+
let monomers: { [type: string]: { [name: string]: Monomer } } = {};
|
|
186
|
+
const types: string[] = [];
|
|
187
|
+
//group monomers by their type
|
|
188
|
+
data.forEach(monomer => {
|
|
189
|
+
let monomerAdd: Monomer = {
|
|
190
|
+
'symbol': monomer['symbol'],
|
|
191
|
+
'name': monomer['name'],
|
|
192
|
+
'molfile': monomer['molfile'],
|
|
193
|
+
'rgroups': monomer['rgroups'],
|
|
194
|
+
'polymerType': monomer['polymerType'],
|
|
195
|
+
'monomerType': monomer['monomerType'],
|
|
196
|
+
'data': {}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
Object.keys(monomer).forEach(prop => {
|
|
200
|
+
if (!expectedMonomerData.includes(prop))
|
|
201
|
+
monomerAdd.data[prop] = monomer[prop];
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (!types.includes(monomer['polymerType'])) {
|
|
205
|
+
monomers[monomer['polymerType']] = {};
|
|
206
|
+
types.push(monomer['polymerType']);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
monomers[monomer['polymerType']][monomer['symbol']] = monomerAdd;
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
monomerLib!.update(monomers);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
//name: Manage Libraries
|
|
216
|
+
//tags: panel, widgets
|
|
217
|
+
//input: column helmColumn {semType: Macromolecule}
|
|
218
|
+
//output: widget result
|
|
219
|
+
export async function libraryPanel(helmColumn: DG.Column): Promise<DG.Widget> {
|
|
220
|
+
//@ts-ignore
|
|
221
|
+
let filesButton: HTMLButtonElement = ui.button('Manage', manageFiles);
|
|
222
|
+
let divInputs: HTMLDivElement = ui.div();
|
|
223
|
+
let librariesList: string[] = (await _package.files.list(`${LIB_PATH}`, false, '')).map(it => it.fileName);
|
|
224
|
+
let uploadedLibraries: string[] = Object.values(await grok.dapi.userDataStorage.get(STORAGE_NAME, true));
|
|
225
|
+
for (let i = 0; i < uploadedLibraries.length; ++i) {
|
|
226
|
+
let libraryName: string = uploadedLibraries[i];
|
|
227
|
+
divInputs.append(ui.boolInput(libraryName, true, async() => {
|
|
228
|
+
grok.dapi.userDataStorage.remove(STORAGE_NAME, libraryName, true);
|
|
229
|
+
await loadLibraries();
|
|
230
|
+
grok.shell.tv.grid.invalidate();
|
|
231
|
+
}).root);
|
|
232
|
+
}
|
|
233
|
+
let unusedLibraries: string[] = librariesList.filter(x => !uploadedLibraries.includes(x));
|
|
234
|
+
for (let i = 0; i < unusedLibraries.length; ++i) {
|
|
235
|
+
let libraryName: string = unusedLibraries[i];
|
|
236
|
+
divInputs.append(ui.boolInput(libraryName, false, () => {
|
|
237
|
+
monomerManager(libraryName);
|
|
238
|
+
grok.dapi.userDataStorage.postValue(STORAGE_NAME, libraryName, libraryName, true);
|
|
239
|
+
}).root);
|
|
240
|
+
}
|
|
241
|
+
return new DG.Widget(ui.splitV([
|
|
242
|
+
divInputs,
|
|
243
|
+
ui.divV([filesButton])
|
|
244
|
+
]));
|
|
45
245
|
}
|
|
46
246
|
|
|
47
247
|
//name: fastaSequenceCellRenderer
|
|
@@ -13,19 +13,34 @@ category('activityCliffs', async () => {
|
|
|
13
13
|
let actCliffsTableViewWithEmptyRows: DG.TableView;
|
|
14
14
|
let actCliffsDfWithEmptyRows: DG.DataFrame;
|
|
15
15
|
|
|
16
|
+
let viewList: DG.ViewBase[] = [];
|
|
17
|
+
let dfList: DG.DataFrame[] = [];
|
|
18
|
+
|
|
19
|
+
before(async () => {
|
|
20
|
+
viewList = [];
|
|
21
|
+
dfList = [];
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
after(async () => {
|
|
25
|
+
for (const view of viewList) view.close();
|
|
26
|
+
for (const df of dfList) grok.shell.closeTable(df);
|
|
27
|
+
});
|
|
28
|
+
|
|
16
29
|
test('activityCliffsOpens', async () => {
|
|
17
30
|
actCliffsDf = await readDataframe('tests/sample_MSA_data.csv');
|
|
31
|
+
dfList.push(actCliffsDf);
|
|
18
32
|
actCliffsTableView = grok.shell.addTableView(actCliffsDf);
|
|
33
|
+
viewList.push(actCliffsTableView);
|
|
34
|
+
|
|
19
35
|
await _testActivityCliffsOpen(actCliffsDf, 57, 'UMAP', 'MSA');
|
|
20
|
-
grok.shell.closeTable(actCliffsDf);
|
|
21
|
-
actCliffsTableView.close();
|
|
22
36
|
});
|
|
23
37
|
|
|
24
38
|
test('activityCliffsWithEmptyRows', async () => {
|
|
25
39
|
actCliffsDfWithEmptyRows = await readDataframe('tests/sample_MSA_data_empty_vals.csv');
|
|
40
|
+
dfList.push(actCliffsDfWithEmptyRows);
|
|
26
41
|
actCliffsTableViewWithEmptyRows = grok.shell.addTableView(actCliffsDfWithEmptyRows);
|
|
42
|
+
viewList.push(actCliffsTableViewWithEmptyRows);
|
|
43
|
+
|
|
27
44
|
await _testActivityCliffsOpen(actCliffsDfWithEmptyRows, 57, 'UMAP', 'MSA');
|
|
28
|
-
grok.shell.closeTable(actCliffsDfWithEmptyRows);
|
|
29
|
-
actCliffsTableViewWithEmptyRows.close();
|
|
30
45
|
});
|
|
31
46
|
});
|
|
@@ -4,7 +4,23 @@ import {createTableView, readDataframe} from './utils';
|
|
|
4
4
|
import * as grok from 'datagrok-api/grok';
|
|
5
5
|
import {SequenceSimilarityViewer} from '../analysis/sequence-similarity-viewer';
|
|
6
6
|
|
|
7
|
+
let viewList: DG.ViewBase[];
|
|
8
|
+
let dfList: DG.DataFrame[];
|
|
9
|
+
|
|
10
|
+
|
|
7
11
|
category('similarity/diversity', async () => {
|
|
12
|
+
|
|
13
|
+
before(async () => {
|
|
14
|
+
viewList = [];
|
|
15
|
+
dfList = [];
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
after(async () => {
|
|
19
|
+
for (const view of viewList) view.close();
|
|
20
|
+
for (const df of dfList) grok.shell.closeTable(df);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
|
|
8
24
|
test('similaritySearchViewer', async () => {
|
|
9
25
|
await _testSimilaritySearchViewer();
|
|
10
26
|
});
|
|
@@ -17,27 +33,27 @@ async function _testSimilaritySearchViewer() {
|
|
|
17
33
|
const molecules = await createTableView('tests/sample_MSA_data.csv');
|
|
18
34
|
const viewer = molecules.addViewer('SequenceSimilaritySearchViewer');
|
|
19
35
|
await delay(100);
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
expect(
|
|
26
|
-
expect(
|
|
27
|
-
expect(
|
|
36
|
+
const similaritySearchViewer = getSearchViewer(viewer, 'SequenceSimilaritySearchViewer');
|
|
37
|
+
viewList.push(similaritySearchViewer);
|
|
38
|
+
viewList.push(molecules);
|
|
39
|
+
if (!similaritySearchViewer.molCol)
|
|
40
|
+
await waitForCompute(similaritySearchViewer);
|
|
41
|
+
expect(similaritySearchViewer.fingerprint, 'Morgan');
|
|
42
|
+
expect(similaritySearchViewer.distanceMetric, 'Tanimoto');
|
|
43
|
+
expect(similaritySearchViewer.scores!.get(0), DG.FLOAT_NULL);
|
|
44
|
+
expect(similaritySearchViewer.idxs!.get(0), 0);
|
|
45
|
+
expect(similaritySearchViewer.molCol!.get(0),
|
|
28
46
|
'D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me');
|
|
29
|
-
expect(
|
|
30
|
-
expect(
|
|
31
|
-
expect(
|
|
47
|
+
expect(similaritySearchViewer.scores!.get(1), 0.4722222089767456);
|
|
48
|
+
expect(similaritySearchViewer.idxs!.get(1), 11);
|
|
49
|
+
expect(similaritySearchViewer.molCol!.get(1),
|
|
32
50
|
'meI/hHis//Aca/meM/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me');
|
|
51
|
+
const waiter = waitForCompute(similaritySearchViewer); /* subscribe for computeCompleted event before start compute */
|
|
33
52
|
molecules.dataFrame.currentRowIdx = 1;
|
|
34
|
-
await
|
|
35
|
-
|
|
36
|
-
expect(
|
|
37
|
-
expect(similaritySearchviewer.molCol!.get(0),
|
|
53
|
+
await waiter;
|
|
54
|
+
expect(similaritySearchViewer.targetMoleculeIdx, 1);
|
|
55
|
+
expect(similaritySearchViewer.molCol!.get(0),
|
|
38
56
|
'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Phe_ab-dehydro/N/D-Orn/D-aThr//Phe_4Me');
|
|
39
|
-
similaritySearchviewer.close();
|
|
40
|
-
molecules.close();
|
|
41
57
|
}
|
|
42
58
|
|
|
43
59
|
|
|
@@ -46,14 +62,14 @@ async function _testDiversitySearchViewer() {
|
|
|
46
62
|
const viewer = molecules.addViewer('SequenceDiversitySearchViewer');
|
|
47
63
|
await delay(10);
|
|
48
64
|
const diversitySearchviewer = getSearchViewer(viewer, 'SequenceDiversitySearchViewer');
|
|
65
|
+
viewList.push(diversitySearchviewer);
|
|
66
|
+
viewList.push(molecules);
|
|
49
67
|
if (!diversitySearchviewer.renderMolIds)
|
|
50
68
|
await waitForCompute(diversitySearchviewer);
|
|
51
69
|
expect(diversitySearchviewer.fingerprint, 'Morgan');
|
|
52
70
|
expect(diversitySearchviewer.distanceMetric, 'Tanimoto');
|
|
53
71
|
expect(diversitySearchviewer.initialized, true);
|
|
54
72
|
expect(diversitySearchviewer.renderMolIds.length > 0, true);
|
|
55
|
-
diversitySearchviewer.close();
|
|
56
|
-
molecules.close();
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
function getSearchViewer(viewer: DG.Viewer, name: string) {
|