@datagrok/bio 2.12.22 → 2.13.2
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/.eslintrc.json +1 -0
- package/CHANGELOG.md +36 -0
- package/dist/231.js +1 -1
- package/dist/231.js.map +1 -1
- package/dist/286.js.map +1 -1
- package/dist/545.js +1 -1
- package/dist/545.js.map +1 -1
- package/dist/package-test.js +2 -2
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +3 -3
- package/dist/package.js.map +1 -1
- package/files/monomer-libraries/sample-lib-Aca-colored.json +37 -0
- package/files/samples/FASTA_UN.csv +4 -0
- package/files/samples/FASTA_UN_MSA.csv +4 -0
- package/package.json +17 -5
- package/src/package-types.ts +11 -0
- package/src/package.ts +13 -14
- package/src/tests/renderers-monomer-placer-tests.ts +10 -12
- package/src/utils/cell-renderer-consts.ts +1 -1
- package/src/utils/cell-renderer.ts +25 -14
- package/src/utils/helm-to-molfile/converter/mol-atoms-v3k.ts +9 -0
- package/src/utils/monomer-cell-renderer.ts +1 -1
- package/src/utils/monomer-lib/library-file-manager/file-validator.ts +13 -7
- package/src/utils/monomer-lib/library-file-manager/ui.ts +16 -10
- package/src/utils/monomer-lib/monomer-lib.ts +23 -10
- package/src/utils/split-to-monomers.ts +1 -1
- package/src/viewers/web-logo-viewer.ts +36 -30
- package/src/widgets/bio-substructure-filter-helm.ts +2 -3
- package/src/widgets/package-settings-editor-widget.ts +11 -1
- package/src/widgets/representations.ts +30 -18
- package/webpack.config.js +2 -8
- package/files/polytool-rules/rules_template.csv +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"monomerType": "Backbone",
|
|
4
|
+
"smiles": "CCCCCCCC[C@H](N[H:1])C([OH:2])=O",
|
|
5
|
+
"name": "2-Aminocapric acid",
|
|
6
|
+
"author": "Pistoia Alliance HELM project",
|
|
7
|
+
"molfile": "HELM Core Monomer library\n RDKit 2D\n\n 14 13 0 0 1 0 0 0 0 0999 V2000\n 0.6430 -4.4293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 1.2375 -5.0013 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.0301 -4.7725 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.6246 -5.3445 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 3.4172 -5.1157 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.0117 -5.6877 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.8044 -5.4589 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.3988 -6.0310 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.1915 -5.8021 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.7859 -6.3742 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 7.5786 -6.1454 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3896 -5.0013 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7951 -4.4293 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 7.1823 -4.7725 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 1 2 1 0\n 2 3 1 0\n 3 4 1 0\n 4 5 1 0\n 5 6 1 0\n 6 7 1 0\n 7 8 1 0\n 9 8 1 0\n 9 10 1 1\n 10 11 1 0\n 9 12 1 0\n 12 13 1 0\n 12 14 2 0\nM RGP 2 11 1 13 2\nM END\n",
|
|
8
|
+
"naturalAnalog": "X",
|
|
9
|
+
"rgroups": [
|
|
10
|
+
{
|
|
11
|
+
"capGroupSMILES": "[*:1][H]",
|
|
12
|
+
"alternateId": "R1-H",
|
|
13
|
+
"capGroupName": "H",
|
|
14
|
+
"label": "R1"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"capGroupSMILES": "O[*:2]",
|
|
18
|
+
"alternateId": "R2-OH",
|
|
19
|
+
"capGroupName": "OH",
|
|
20
|
+
"label": "R2"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"meta": {
|
|
24
|
+
"colors": {
|
|
25
|
+
"default": {
|
|
26
|
+
"line": "#202020",
|
|
27
|
+
"text": "#202020",
|
|
28
|
+
"background": "#60FF40"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"createDate": null,
|
|
33
|
+
"id": 0,
|
|
34
|
+
"polymerType": "PEPTIDE",
|
|
35
|
+
"symbol": "Aca"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
seq
|
|
2
|
+
[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI]
|
|
3
|
+
[meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
|
|
4
|
+
[Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
seq
|
|
2
|
+
[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D
|
|
3
|
+
[meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
|
|
4
|
+
[Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Aleksandr Tanas",
|
|
6
6
|
"email": "atanas@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.
|
|
8
|
+
"version": "2.13.2",
|
|
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",
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
"directory": "packages/Bio"
|
|
14
14
|
},
|
|
15
15
|
"properties": [
|
|
16
|
+
{
|
|
17
|
+
"name": "MonomerWidthMode",
|
|
18
|
+
"propertyType": "string",
|
|
19
|
+
"choices": [
|
|
20
|
+
"short",
|
|
21
|
+
"long"
|
|
22
|
+
],
|
|
23
|
+
"defaultValue": "short",
|
|
24
|
+
"nullable": false
|
|
25
|
+
},
|
|
16
26
|
{
|
|
17
27
|
"name": "MaxMonomerLength",
|
|
18
28
|
"propertyType": "int",
|
|
@@ -34,18 +44,18 @@
|
|
|
34
44
|
],
|
|
35
45
|
"dependencies": {
|
|
36
46
|
"@biowasm/aioli": "^3.1.0",
|
|
37
|
-
"@datagrok-libraries/bio": "^5.
|
|
47
|
+
"@datagrok-libraries/bio": "^5.42.3",
|
|
38
48
|
"@datagrok-libraries/chem-meta": "^1.2.5",
|
|
39
49
|
"@datagrok-libraries/math": "^1.1.5",
|
|
40
|
-
"@datagrok-libraries/ml": "^6.6.
|
|
50
|
+
"@datagrok-libraries/ml": "^6.6.12",
|
|
41
51
|
"@datagrok-libraries/tutorials": "^1.3.12",
|
|
42
|
-
"@datagrok-libraries/utils": "^4.2.
|
|
52
|
+
"@datagrok-libraries/utils": "^4.2.11",
|
|
43
53
|
"@webgpu/types": "^0.1.40",
|
|
44
54
|
"ajv": "^8.12.0",
|
|
45
55
|
"ajv-errors": "^3.0.0",
|
|
46
56
|
"cash-dom": "^8.0.0",
|
|
47
57
|
"css-loader": "^6.7.3",
|
|
48
|
-
"datagrok-api": "^1.
|
|
58
|
+
"datagrok-api": "^1.18.6",
|
|
49
59
|
"dayjs": "^1.11.4",
|
|
50
60
|
"fastest-levenshtein": "^1.0.16",
|
|
51
61
|
"openchemlib": "^7.2.3",
|
|
@@ -55,6 +65,8 @@
|
|
|
55
65
|
"wu": "latest"
|
|
56
66
|
},
|
|
57
67
|
"devDependencies": {
|
|
68
|
+
"@datagrok-libraries/helm-web-editor": "^1.1.5",
|
|
69
|
+
"@datagrok-libraries/js-draw-lite": "^0.0.3",
|
|
58
70
|
"@datagrok/chem": "^1.9.2",
|
|
59
71
|
"@datagrok/dendrogram": "^1.2.29",
|
|
60
72
|
"@datagrok/helm": "^2.2.1",
|
package/src/package-types.ts
CHANGED
|
@@ -4,9 +4,11 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
|
|
5
5
|
import {Observable, Subject} from 'rxjs';
|
|
6
6
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
7
|
+
import {MonomerWidthMode} from './utils/cell-renderer-consts';
|
|
7
8
|
|
|
8
9
|
/** Names of package properties/settings declared in properties section of {@link './package.json'} */
|
|
9
10
|
export const enum BioPackagePropertiesNames {
|
|
11
|
+
MonomerWidthMode = 'MonomerWidthMode',
|
|
10
12
|
MaxMonomerLength = 'MaxMonomerLength',
|
|
11
13
|
TooltipWebLogo = 'TooltipWebLogo',
|
|
12
14
|
DefaultSeparator = 'DefaultSeparator',
|
|
@@ -17,6 +19,15 @@ export class BioPackageProperties extends Map<string, any> {
|
|
|
17
19
|
private _onPropertyChanged: Subject<string> = new Subject<string>();
|
|
18
20
|
public get onPropertyChanged(): Observable<string> { return this._onPropertyChanged; }
|
|
19
21
|
|
|
22
|
+
public get MonomerWidthMode(): MonomerWidthMode {
|
|
23
|
+
return super.get(BioPackagePropertiesNames.MonomerWidthMode) as MonomerWidthMode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public set MonomerWidthMode(value: MonomerWidthMode) {
|
|
27
|
+
super.set(BioPackagePropertiesNames.MonomerWidthMode, value);
|
|
28
|
+
this._onPropertyChanged.next(BioPackagePropertiesNames.MonomerWidthMode);
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
/** Monomer name maximum length displayed in short mode. */
|
|
21
32
|
public get MaxMonomerLength(): number {
|
|
22
33
|
return super.get(BioPackagePropertiesNames.MaxMonomerLength) as number;
|
package/src/package.ts
CHANGED
|
@@ -3,8 +3,6 @@ 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
|
-
|
|
8
6
|
import {Options} from '@datagrok-libraries/utils/src/type-declarations';
|
|
9
7
|
import {DimReductionBaseEditor, PreprocessFunctionReturnType}
|
|
10
8
|
from '@datagrok-libraries/ml/src/functionEditors/dimensionality-reduction-editor';
|
|
@@ -78,6 +76,7 @@ import {generateLongSequence, generateLongSequence2} from '@datagrok-libraries/b
|
|
|
78
76
|
|
|
79
77
|
import {CyclizedNotationProvider} from './utils/cyclized';
|
|
80
78
|
import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
|
|
79
|
+
import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
|
|
81
80
|
|
|
82
81
|
export const _package = new BioPackage();
|
|
83
82
|
|
|
@@ -109,7 +108,7 @@ let monomerLib: IMonomerLib | null = null;
|
|
|
109
108
|
|
|
110
109
|
//tags: init
|
|
111
110
|
export async function initBio() {
|
|
112
|
-
const logPrefix = 'Bio: initBio()';
|
|
111
|
+
const logPrefix = 'Bio: _package.initBio()';
|
|
113
112
|
_package.logger.debug(`${logPrefix}, start`);
|
|
114
113
|
const module = await grok.functions.call('Chem:getRdKitModule');
|
|
115
114
|
const t1: number = window.performance.now();
|
|
@@ -152,7 +151,7 @@ export async function initBio() {
|
|
|
152
151
|
|
|
153
152
|
hydrophobPalette = new SeqPaletteCustom(palette);
|
|
154
153
|
|
|
155
|
-
_package.logger.debug(
|
|
154
|
+
_package.logger.debug(`${logPrefix}, end`);
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
//name: sequenceTooltip
|
|
@@ -292,16 +291,16 @@ export function SeqActivityCliffsEditor(call: DG.FuncCall) {
|
|
|
292
291
|
|
|
293
292
|
// -- Package settings editor --
|
|
294
293
|
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
294
|
+
//name: packageSettingsEditor
|
|
295
|
+
//description: The database connection
|
|
296
|
+
//tags: packageSettingsEditor
|
|
297
|
+
//input: object propList
|
|
298
|
+
//output: widget result
|
|
299
|
+
export function packageSettingsEditor(propList: DG.Property[]): DG.Widget {
|
|
300
|
+
const widget = new PackageSettingsEditorWidget(propList);
|
|
301
|
+
widget.init().then(); // Ignore promise returned
|
|
302
|
+
return widget as DG.Widget;
|
|
303
|
+
}
|
|
305
304
|
|
|
306
305
|
// -- Cell renderers --
|
|
307
306
|
|
|
@@ -108,8 +108,6 @@ id3,QHIRE--LT
|
|
|
108
108
|
|
|
109
109
|
for (const [testName, testData] of Object.entries(tests)) {
|
|
110
110
|
test(`getPosition-${testName}`, async () => {
|
|
111
|
-
const libHelper = await getMonomerLibHelper();
|
|
112
|
-
const monomerLib = libHelper.getBioLib();
|
|
113
111
|
const df: DG.DataFrame = DG.DataFrame.fromCsv(testData.csv);
|
|
114
112
|
await grok.data.detectSemanticTypes(df);
|
|
115
113
|
const seqCol: DG.Column = df.getCol('seq');
|
|
@@ -117,16 +115,16 @@ id3,QHIRE--LT
|
|
|
117
115
|
const monLength: number = 3;
|
|
118
116
|
const charWidth: number = 7;
|
|
119
117
|
const sepWidth: number = 12;
|
|
120
|
-
const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger, monLength,
|
|
119
|
+
() => {
|
|
120
|
+
const sh = SeqHandler.forColumn(seqCol);
|
|
121
|
+
return {
|
|
122
|
+
seqHandler: sh,
|
|
123
|
+
monomerCharWidth: charWidth,
|
|
124
|
+
separatorWidth: sepWidth,
|
|
125
|
+
monomerToShort: monomerToShort,
|
|
126
|
+
};
|
|
127
|
+
});
|
|
130
128
|
|
|
131
129
|
const width: number = 10000;
|
|
132
130
|
const testList = testData.testList;
|
|
@@ -28,7 +28,7 @@ export const enum Temps {
|
|
|
28
28
|
export const enum tempTAGS {
|
|
29
29
|
referenceSequence = 'reference-sequence',
|
|
30
30
|
currentWord = 'current-word',
|
|
31
|
-
|
|
31
|
+
monomerWidthMode = 'monomer-width-mode',
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
// export const MacromoleculeCellRendererDefaults = new class {
|
|
@@ -26,7 +26,7 @@ import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-re
|
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
28
|
Temps as mmcrTemps, Tags as mmcrTags,
|
|
29
|
-
tempTAGS, rendererSettingsChangedState
|
|
29
|
+
tempTAGS, rendererSettingsChangedState, MonomerWidthMode
|
|
30
30
|
} from '../utils/cell-renderer-consts';
|
|
31
31
|
import * as C from './constants';
|
|
32
32
|
|
|
@@ -155,8 +155,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
155
155
|
let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
|
|
156
156
|
|
|
157
157
|
// Cell renderer settings
|
|
158
|
-
const tempMonomerWidth: string | null = tableColTemp[tempTAGS.
|
|
159
|
-
const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth :
|
|
158
|
+
const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidthMode];
|
|
159
|
+
const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth :
|
|
160
|
+
(_package.properties?.MonomerWidthMode ?? MonomerWidthMode.short);
|
|
160
161
|
if (monomerWidth === 'short') {
|
|
161
162
|
// Renderer can start to work before Bio package initialized, in that time _package.properties is null.
|
|
162
163
|
// TODO: Render function is available but package init method is not completed
|
|
@@ -169,20 +170,23 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
169
170
|
getGridCellRendererBack<string, MonomerPlacer>(gridCell);
|
|
170
171
|
let seqColTemp: MonomerPlacer = temp.rendererBack;
|
|
171
172
|
if (!seqColTemp) {
|
|
172
|
-
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
|
|
173
|
+
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
|
|
173
174
|
() => {
|
|
174
175
|
const sh = SeqHandler.forColumn(tableCol);
|
|
175
176
|
return {
|
|
176
177
|
seqHandler: sh,
|
|
177
178
|
monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
|
|
178
|
-
monomerToShort: monomerToShortFunction,
|
|
179
|
+
monomerToShort: monomerToShortFunction,
|
|
179
180
|
};
|
|
180
181
|
});
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
g.save();
|
|
184
185
|
try {
|
|
185
|
-
if (
|
|
186
|
+
if (
|
|
187
|
+
tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true ||
|
|
188
|
+
seqColTemp.monomerLengthLimit != maxLengthOfMonomer
|
|
189
|
+
) {
|
|
186
190
|
gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
|
|
187
191
|
// this event means that the mm renderer settings have changed,
|
|
188
192
|
// particularly monomer representation and max width.
|
|
@@ -245,9 +249,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
245
249
|
g.fillStyle = undefinedColor;
|
|
246
250
|
const last = posIdx === subParts.length - 1;
|
|
247
251
|
/*x1 = */
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
maxLengthWordsSum, posIdx, gridCell
|
|
252
|
+
const opts = {
|
|
253
|
+
color: color, pivot: 0, left: true, transparencyRate: 1.0, separator: separator, last: last,
|
|
254
|
+
drawStyle: drawStyle, maxWord: maxLengthWordsSum, wordIdx: posIdx, gridCell: gridCell,
|
|
255
|
+
referenceSequence: referenceSequence, maxLengthOfMonomer: maxLengthOfMonomer,
|
|
256
|
+
monomerTextSizeMap: seqColTemp._monomerLengthMap, logger: _package.logger
|
|
257
|
+
};
|
|
258
|
+
printLeftOrCentered(g, amino, x + this.padding, y, w, h, opts);
|
|
251
259
|
if (minDistanceRenderer > w) break;
|
|
252
260
|
}
|
|
253
261
|
} catch (err: any) {
|
|
@@ -350,14 +358,17 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
350
358
|
|
|
351
359
|
if (amino1 != amino2) {
|
|
352
360
|
const color2 = palette.get(amino2);
|
|
353
|
-
const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h,
|
|
354
|
-
|
|
361
|
+
const subX0 = printLeftOrCentered(g, amino1, updatedX, updatedY - vShift, w, h,
|
|
362
|
+
{color: color1, pivot: 0, left: true});
|
|
363
|
+
const subX1 = printLeftOrCentered(g, amino2, updatedX, updatedY + vShift, w, h,
|
|
364
|
+
{color: color2, pivot: 0, left: true});
|
|
355
365
|
updatedX = Math.max(subX1, subX0);
|
|
356
366
|
if (molDifferences)
|
|
357
367
|
molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
|
|
358
368
|
} else {
|
|
359
369
|
//
|
|
360
|
-
updatedX = printLeftOrCentered(
|
|
370
|
+
updatedX = printLeftOrCentered(g, amino1, updatedX, updatedY, w, h,
|
|
371
|
+
{color: color1, pivot: 0, left: true, transparencyRate: 0.5});
|
|
361
372
|
}
|
|
362
373
|
updatedX += 4;
|
|
363
374
|
}
|
|
@@ -382,8 +393,8 @@ function createDifferenceCanvas(amino1: string, amino2: string, color1: string,
|
|
|
382
393
|
canvas.width = width + 4;
|
|
383
394
|
context.font = '12px monospace';
|
|
384
395
|
context.textBaseline = 'top';
|
|
385
|
-
printLeftOrCentered(0, y - shift, width, h,
|
|
386
|
-
printLeftOrCentered(0, y + shift, width, h,
|
|
396
|
+
printLeftOrCentered(context, amino1, 0, y - shift, width, h, {color: color1, pivot: 0, left: true});
|
|
397
|
+
printLeftOrCentered(context, amino2, 0, y + shift, width, h, {color: color2, pivot: 0, left: true});
|
|
387
398
|
return canvas;
|
|
388
399
|
}
|
|
389
400
|
|
|
@@ -34,5 +34,14 @@ export class MolfileAtomsV3K extends MolfileAtoms {
|
|
|
34
34
|
}).replace(rGroupsRegex, '');
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
replaceRGroupSymbolByElement(atomIdx: number, newElementSymbol: string): void {
|
|
39
|
+
super.replaceRGroupSymbolByElement(atomIdx, newElementSymbol);
|
|
40
|
+
// rdkit can generate (out of thin air) masses for r groups, so we need to remove them as well.
|
|
41
|
+
//they are at the end of the line after coordinates and other data
|
|
42
|
+
const lineInfo = this.rawAtomLines[atomIdx].substring(3).split(' ');
|
|
43
|
+
if (lineInfo.length > 7)
|
|
44
|
+
this.rawAtomLines[atomIdx] = `M ${lineInfo.slice(0, 7).join(' ')}`;
|
|
45
|
+
}
|
|
37
46
|
}
|
|
38
47
|
|
|
@@ -2,10 +2,10 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
|
|
5
|
+
import {PolymerType} from '@datagrok-libraries/bio/src/helm/types';
|
|
5
6
|
import {ALPHABET, getPaletteByType, monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
7
|
import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
|
|
7
8
|
import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
8
|
-
import {PolymerType} from '@datagrok-libraries/bio/src/types';
|
|
9
9
|
|
|
10
10
|
import * as C from './constants';
|
|
11
11
|
import {getMonomerLib} from '../package';
|
|
@@ -2,6 +2,12 @@ import {JSONSchemaType, ValidateFunction} from 'ajv';
|
|
|
2
2
|
import Ajv2020 from 'ajv/dist/2020';
|
|
3
3
|
import addErrors from 'ajv-errors';
|
|
4
4
|
|
|
5
|
+
const NA_CODE: string = '#N/A';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
HELM_REQUIRED_FIELD as REQ,
|
|
9
|
+
} from '@datagrok-libraries/bio/src/utils/const';
|
|
10
|
+
|
|
5
11
|
export class MonomerLibFileValidator {
|
|
6
12
|
private validateMonomerSchema: ValidateFunction<any>;
|
|
7
13
|
|
|
@@ -14,25 +20,24 @@ export class MonomerLibFileValidator {
|
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
validateFile(fileContent: string, fileName: string): boolean {
|
|
17
|
-
const jsonContent = this.parseJson(fileContent);
|
|
23
|
+
const jsonContent = this.parseJson(fileContent, fileName);
|
|
18
24
|
if (jsonContent === null)
|
|
19
25
|
return false;
|
|
20
26
|
|
|
21
27
|
if (!Array.isArray(jsonContent)) {
|
|
22
|
-
console.warn(
|
|
23
|
-
'
|
|
24
|
-
);
|
|
28
|
+
console.warn(`Bio: Monomer Library File Validator file '${fileName}': Invalid JSON format: ` +
|
|
29
|
+
'The file must contain an array of monomers.');
|
|
25
30
|
return false;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
return this.validateJsonContent(jsonContent, fileName);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
private parseJson(fileContent: string): any[] | null {
|
|
36
|
+
private parseJson(fileContent: string, fileName: string): any[] | null {
|
|
32
37
|
try {
|
|
33
38
|
return JSON.parse(fileContent);
|
|
34
39
|
} catch (e) {
|
|
35
|
-
console.error(
|
|
40
|
+
console.error(`Bio: Monomer Library File Validator file '${fileName}': Invalid JSON format:`, e);
|
|
36
41
|
return null;
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -40,10 +45,11 @@ export class MonomerLibFileValidator {
|
|
|
40
45
|
private validateJsonContent(jsonContent: any[], fileName: string): boolean {
|
|
41
46
|
let isValid = true;
|
|
42
47
|
for (const monomer of jsonContent) {
|
|
48
|
+
const name = monomer[REQ.SYMBOL] ?? monomer[REQ.ID] ?? monomer[REQ.NAME] ?? NA_CODE;
|
|
43
49
|
isValid = this.validateMonomerSchema(monomer);
|
|
44
50
|
if (!isValid) {
|
|
45
51
|
console.warn(
|
|
46
|
-
`Bio: Monomer Library File Validator
|
|
52
|
+
`Bio: Monomer Library File Validator file ${fileName}, monomer '${name}' violating JSON schema:`,
|
|
47
53
|
monomer,
|
|
48
54
|
'\nError reason: ',
|
|
49
55
|
this.validateMonomerSchema.errors,
|
|
@@ -14,6 +14,7 @@ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
|
14
14
|
import {getMonomerLibHelper, IMonomerLibFileManager} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
15
15
|
|
|
16
16
|
import {MonomerLibFileEventManager} from './event-manager';
|
|
17
|
+
import {_package} from '../../../package';
|
|
17
18
|
|
|
18
19
|
export async function showManageLibrariesDialog(): Promise<void> {
|
|
19
20
|
await DialogWrapper.showDialog();
|
|
@@ -89,7 +90,8 @@ class MonomerLibraryManagerWidget {
|
|
|
89
90
|
|
|
90
91
|
class LibraryControlsManager {
|
|
91
92
|
private constructor(
|
|
92
|
-
private fileManager: IMonomerLibFileManager
|
|
93
|
+
private fileManager: IMonomerLibFileManager,
|
|
94
|
+
private readonly userLibSettings: UserLibSettings,
|
|
93
95
|
) {
|
|
94
96
|
this.fileManager.eventManager.updateUIControlsRequested$.subscribe(() => {
|
|
95
97
|
this.updateControlsForm();
|
|
@@ -99,13 +101,18 @@ class LibraryControlsManager {
|
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
private
|
|
104
|
+
private toLog(): string {
|
|
105
|
+
return `LibraryControlsManager<#>`;
|
|
106
|
+
}
|
|
103
107
|
|
|
104
108
|
static async createControlsForm(): Promise<HTMLElement> {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
+
const logPrefix = 'LibraryControlsForm.createControlsForm()';
|
|
110
|
+
_package.logger.debug(`${logPrefix}, start`);
|
|
111
|
+
const [fileManager, userLibSettings] = await Promise.all([
|
|
112
|
+
getMonomerLibHelper().then((libHelper) => libHelper.getFileManager()),
|
|
113
|
+
await getUserLibSettings(),
|
|
114
|
+
]);
|
|
115
|
+
const manager = new LibraryControlsManager(fileManager, userLibSettings);
|
|
109
116
|
|
|
110
117
|
return manager._createControlsForm();
|
|
111
118
|
}
|
|
@@ -118,10 +125,6 @@ class LibraryControlsManager {
|
|
|
118
125
|
return inputsForm;
|
|
119
126
|
}
|
|
120
127
|
|
|
121
|
-
private async initialize(): Promise<void> {
|
|
122
|
-
this.userLibSettings = await getUserLibSettings();
|
|
123
|
-
};
|
|
124
|
-
|
|
125
128
|
private updateControlsForm(): void {
|
|
126
129
|
const updatedForm = this._createControlsForm();
|
|
127
130
|
$('.monomer-lib-controls-form').replaceWith(updatedForm);
|
|
@@ -133,6 +136,8 @@ class LibraryControlsManager {
|
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
private createLibInput(libFileName: string): DG.InputBase<boolean | null> {
|
|
139
|
+
const logPrefix = `${this.toLog()}.createLibInput()`;
|
|
140
|
+
_package.logger.debug(`${logPrefix}, libFileName = '${libFileName}', start`);
|
|
136
141
|
const isMonomerLibrarySelected = !this.userLibSettings.exclude.includes(libFileName);
|
|
137
142
|
const libInput = ui.boolInput(
|
|
138
143
|
libFileName,
|
|
@@ -144,6 +149,7 @@ class LibraryControlsManager {
|
|
|
144
149
|
const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName));
|
|
145
150
|
ui.tooltip.bind(deleteIcon, `Delete ${libFileName}`);
|
|
146
151
|
libInput.addOptions(deleteIcon);
|
|
152
|
+
_package.logger.debug(`${logPrefix}, libFileName = '${libFileName}', end`);
|
|
147
153
|
return libInput;
|
|
148
154
|
}
|
|
149
155
|
|
|
@@ -6,17 +6,18 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
import wu from 'wu';
|
|
7
7
|
import {Observable, Subject} from 'rxjs';
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
} from '@datagrok-libraries/bio/src/types';
|
|
12
|
-
import {PolymerTypes} from '@datagrok-libraries/bio/src/utils/const';
|
|
9
|
+
import {MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
|
|
10
|
+
import {IMonomerLib, Monomer, MonomerLibSummaryType, RGroup} from '@datagrok-libraries/bio/src/types';
|
|
13
11
|
import {HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
|
|
14
12
|
import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
|
|
15
13
|
import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
16
14
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
15
|
+
import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
|
|
17
16
|
|
|
18
17
|
import '../../../css/cell-renderer.css';
|
|
19
18
|
|
|
19
|
+
import {_package} from '../../package';
|
|
20
|
+
|
|
20
21
|
/** Wrapper for monomers obtained from different sources. For managing monomere
|
|
21
22
|
* libraries, use MolfileHandler class instead */
|
|
22
23
|
export class MonomerLib implements IMonomerLib {
|
|
@@ -75,7 +76,8 @@ export class MonomerLib implements IMonomerLib {
|
|
|
75
76
|
return m;
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
getMonomer(polymerType: PolymerType, argMonomerSymbol: string): Monomer | null {
|
|
79
|
+
getMonomer(polymerType: PolymerType | null, argMonomerSymbol: string): Monomer | null {
|
|
80
|
+
const logPrefix = `Bio: MonomerLib.getMonomer()`;
|
|
79
81
|
// Adjust RNA's 'R' for ribose to 'r' and 'P' for phosphate to 'p' for case-sensitive monomer names.
|
|
80
82
|
// There are uppercase 'R' and 'P' at RNA samples in test data 'helm2.csv' but lowercase in HELMCoreLibrary.json
|
|
81
83
|
let monomerSymbol = argMonomerSymbol;
|
|
@@ -84,10 +86,20 @@ export class MonomerLib implements IMonomerLib {
|
|
|
84
86
|
if (polymerType == 'RNA' && monomerSymbol == 'P')
|
|
85
87
|
monomerSymbol = 'p';
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
let res: Monomer | null = null;
|
|
90
|
+
|
|
91
|
+
if (!polymerType) {
|
|
92
|
+
_package.logger.warning(`${logPrefix} symbol '${argMonomerSymbol}', polymerType not specified.`);
|
|
93
|
+
// Assume any polymer type
|
|
94
|
+
for (const [polymerType, dict] of Object.entries(this._monomers)) {
|
|
95
|
+
res = dict[monomerSymbol];
|
|
96
|
+
if (res) break;
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
const dict = this._monomers[polymerType];
|
|
100
|
+
res = dict ? dict[monomerSymbol] : null;
|
|
101
|
+
}
|
|
102
|
+
return res;
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
getPolymerTypes(): PolymerType[] {
|
|
@@ -231,6 +243,7 @@ export class MonomerLib implements IMonomerLib {
|
|
|
231
243
|
const chemOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
232
244
|
let structureEl: HTMLElement;
|
|
233
245
|
if (monomer.molfile) {
|
|
246
|
+
//
|
|
234
247
|
structureEl = grok.chem.svgMol(monomer.molfile, undefined, undefined, chemOptions);
|
|
235
248
|
} else if (monomer.smiles) {
|
|
236
249
|
structureEl = ui.divV([
|
|
@@ -245,7 +258,7 @@ export class MonomerLib implements IMonomerLib {
|
|
|
245
258
|
{style: {display: 'flex', flexDirection: 'row', justifyContent: 'center', margin: '6px'}}));
|
|
246
259
|
|
|
247
260
|
// Source
|
|
248
|
-
res.append(ui.divText(monomer.lib?.source ?? '
|
|
261
|
+
res.append(ui.divText(monomer.lib?.source ?? 'Missed in libraries'));
|
|
249
262
|
|
|
250
263
|
// const label = (s: string) => {
|
|
251
264
|
// return ui.label(s /* span ? */, {classes: 'ui-input-label'});
|
|
@@ -31,7 +31,7 @@ export async function splitToMonomersUI(table: DG.DataFrame, seqCol: DG.Column<s
|
|
|
31
31
|
colNameRe.lastIndex = 0;
|
|
32
32
|
const ma = srcName.match(colNameRe);
|
|
33
33
|
if (!ma) return srcName;
|
|
34
|
-
return `${ma[1]} (${parseInt(ma[2] ?? 0) + 1})`;
|
|
34
|
+
return `${ma[1]} (${parseInt(ma[2] ?? '0') + 1})`;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
// if (tempDf.columns.length === 0) return;
|