@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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.0.32",
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.16",
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 similaritySearchviewer = getSearchViewer(viewer, 'SequenceSimilaritySearchViewer');
21
- if (!similaritySearchviewer.molCol)
22
- await waitForCompute(similaritySearchviewer);
23
- expect(similaritySearchviewer.fingerprint, 'Morgan');
24
- expect(similaritySearchviewer.distanceMetric, 'Tanimoto');
25
- expect(similaritySearchviewer.scores!.get(0), DG.FLOAT_NULL);
26
- expect(similaritySearchviewer.idxs!.get(0), 0);
27
- expect(similaritySearchviewer.molCol!.get(0),
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(similaritySearchviewer.scores!.get(1), 0.4722222089767456);
30
- expect(similaritySearchviewer.idxs!.get(1), 11);
31
- expect(similaritySearchviewer.molCol!.get(1),
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 delay(100);
35
- await waitForCompute(similaritySearchviewer);
36
- expect(similaritySearchviewer.targetMoleculeIdx, 1);
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) {