@datagrok/bio 2.12.23 → 2.13.3
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 +37 -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 +12 -7
- package/src/package-types.ts +9 -5
- package/src/package.ts +10 -4
- package/src/tests/renderers-monomer-placer-tests.ts +10 -12
- package/src/utils/cell-renderer-consts.ts +3 -11
- package/src/utils/cell-renderer.ts +32 -23
- 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 +28 -18
- package/src/widgets/representations.ts +66 -58
- package/webpack.config.js +3 -9
- 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.3",
|
|
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",
|
|
@@ -15,18 +15,21 @@
|
|
|
15
15
|
"properties": [
|
|
16
16
|
{
|
|
17
17
|
"name": "MaxMonomerLength",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"description": "The max length of monomer symbol displayed without shortening, 'long' to no limit",
|
|
19
|
+
"propertyType": "string",
|
|
20
|
+
"defaultValue": "4",
|
|
20
21
|
"nullable": false
|
|
21
22
|
},
|
|
22
23
|
{
|
|
23
24
|
"name": "TooltipWebLogo",
|
|
25
|
+
"description": "Display WebLogo in a Macromolecule column header tooltip",
|
|
24
26
|
"propertyType": "bool",
|
|
25
27
|
"defaultValue": "true",
|
|
26
28
|
"nullable": false
|
|
27
29
|
},
|
|
28
30
|
{
|
|
29
31
|
"name": "DefaultSeparator",
|
|
32
|
+
"description": "Default separator using to convert sequences into separator notation",
|
|
30
33
|
"propertyType": "string",
|
|
31
34
|
"defaultValue": ".",
|
|
32
35
|
"nullable": false
|
|
@@ -34,18 +37,18 @@
|
|
|
34
37
|
],
|
|
35
38
|
"dependencies": {
|
|
36
39
|
"@biowasm/aioli": "^3.1.0",
|
|
37
|
-
"@datagrok-libraries/bio": "^5.
|
|
40
|
+
"@datagrok-libraries/bio": "^5.42.3",
|
|
38
41
|
"@datagrok-libraries/chem-meta": "^1.2.5",
|
|
39
42
|
"@datagrok-libraries/math": "^1.1.5",
|
|
40
|
-
"@datagrok-libraries/ml": "^6.6.
|
|
43
|
+
"@datagrok-libraries/ml": "^6.6.12",
|
|
41
44
|
"@datagrok-libraries/tutorials": "^1.3.12",
|
|
42
|
-
"@datagrok-libraries/utils": "^4.2.
|
|
45
|
+
"@datagrok-libraries/utils": "^4.2.11",
|
|
43
46
|
"@webgpu/types": "^0.1.40",
|
|
44
47
|
"ajv": "^8.12.0",
|
|
45
48
|
"ajv-errors": "^3.0.0",
|
|
46
49
|
"cash-dom": "^8.0.0",
|
|
47
50
|
"css-loader": "^6.7.3",
|
|
48
|
-
"datagrok-api": "^1.
|
|
51
|
+
"datagrok-api": "^1.18.6",
|
|
49
52
|
"dayjs": "^1.11.4",
|
|
50
53
|
"fastest-levenshtein": "^1.0.16",
|
|
51
54
|
"openchemlib": "^7.2.3",
|
|
@@ -55,6 +58,8 @@
|
|
|
55
58
|
"wu": "latest"
|
|
56
59
|
},
|
|
57
60
|
"devDependencies": {
|
|
61
|
+
"@datagrok-libraries/helm-web-editor": "^1.1.5",
|
|
62
|
+
"@datagrok-libraries/js-draw-lite": "^0.0.3",
|
|
58
63
|
"@datagrok/chem": "^1.9.2",
|
|
59
64
|
"@datagrok/dendrogram": "^1.2.29",
|
|
60
65
|
"@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 {Group} from 'datagrok-api/dg';
|
|
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,13 +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
|
|
|
20
|
-
/** Monomer
|
|
21
|
-
public get MaxMonomerLength(): number {
|
|
22
|
-
|
|
22
|
+
/** Monomer symbol maximum length displayed, null for unlimited. */
|
|
23
|
+
public get MaxMonomerLength(): number | null {
|
|
24
|
+
const vs = super.get(BioPackagePropertiesNames.MaxMonomerLength);
|
|
25
|
+
return vs === 'long' ? null : parseInt(vs);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
public set MaxMonomerLength(value: number) {
|
|
26
|
-
|
|
28
|
+
public set MaxMonomerLength(value: number | null) {
|
|
29
|
+
const vs = value === null ? 'long' : value.toString();
|
|
30
|
+
super.set(BioPackagePropertiesNames.MaxMonomerLength, vs);
|
|
27
31
|
this._onPropertyChanged.next(BioPackagePropertiesNames.MaxMonomerLength);
|
|
28
32
|
}
|
|
29
33
|
|
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,8 @@ 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';
|
|
80
|
+
import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
81
81
|
|
|
82
82
|
export const _package = new BioPackage();
|
|
83
83
|
|
|
@@ -109,13 +109,19 @@ let monomerLib: IMonomerLib | null = null;
|
|
|
109
109
|
|
|
110
110
|
//tags: init
|
|
111
111
|
export async function initBio() {
|
|
112
|
-
const logPrefix = 'Bio: initBio()';
|
|
112
|
+
const logPrefix = 'Bio: _package.initBio()';
|
|
113
113
|
_package.logger.debug(`${logPrefix}, start`);
|
|
114
114
|
const module = await grok.functions.call('Chem:getRdKitModule');
|
|
115
115
|
const t1: number = window.performance.now();
|
|
116
116
|
await Promise.all([
|
|
117
117
|
(async () => {
|
|
118
118
|
const monomerLibManager = await MonomerLibManager.getInstance();
|
|
119
|
+
// Fix user lib settings for explicit stuck from a terminated test
|
|
120
|
+
const libSettings = await getUserLibSettings();
|
|
121
|
+
if (libSettings.explicit) {
|
|
122
|
+
libSettings.explicit = [];
|
|
123
|
+
await setUserLibSettings(libSettings);
|
|
124
|
+
}
|
|
119
125
|
await monomerLibManager.loadLibraries();
|
|
120
126
|
monomerLib = monomerLibManager.getBioLib();
|
|
121
127
|
})(),
|
|
@@ -152,7 +158,7 @@ export async function initBio() {
|
|
|
152
158
|
|
|
153
159
|
hydrophobPalette = new SeqPaletteCustom(palette);
|
|
154
160
|
|
|
155
|
-
_package.logger.debug(
|
|
161
|
+
_package.logger.debug(`${logPrefix}, end`);
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
//name: sequenceTooltip
|
|
@@ -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;
|
|
@@ -2,33 +2,25 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
-
export enum MonomerWidthMode {
|
|
6
|
-
long = 'long',
|
|
7
|
-
short = 'short',
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const enum Tags {
|
|
11
|
-
RendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
|
|
12
|
-
}
|
|
13
|
-
|
|
14
5
|
export const rendererSettingsChangedState = {
|
|
15
6
|
true: '1',
|
|
16
7
|
false: '0',
|
|
17
8
|
};
|
|
18
9
|
|
|
19
10
|
export const enum Temps {
|
|
20
|
-
|
|
11
|
+
maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
|
|
21
12
|
colorCode = '.mm.cellRenderer.colorCode',
|
|
22
13
|
compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
|
|
23
14
|
highlightDifference = '.mm.cellRenderer.highlightDifference',
|
|
24
15
|
gapLength = '.mm.cellRenderer.gapLength',
|
|
25
16
|
monomerPlacer = '.mm.cellRenderer.monomerPlacer',
|
|
17
|
+
|
|
18
|
+
rendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
export const enum tempTAGS {
|
|
29
22
|
referenceSequence = 'reference-sequence',
|
|
30
23
|
currentWord = 'current-word',
|
|
31
|
-
monomerWidth = 'monomer-width',
|
|
32
24
|
}
|
|
33
25
|
|
|
34
26
|
// export const MacromoleculeCellRendererDefaults = new class {
|
|
@@ -25,8 +25,8 @@ import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/typ
|
|
|
25
25
|
import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
26
26
|
|
|
27
27
|
import {
|
|
28
|
-
Temps as mmcrTemps,
|
|
29
|
-
tempTAGS, rendererSettingsChangedState
|
|
28
|
+
Temps as mmcrTemps,
|
|
29
|
+
tempTAGS, rendererSettingsChangedState, Temps
|
|
30
30
|
} from '../utils/cell-renderer-consts';
|
|
31
31
|
import * as C from './constants';
|
|
32
32
|
|
|
@@ -152,43 +152,45 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
152
152
|
|
|
153
153
|
let gapLength = 0;
|
|
154
154
|
const msaGapLength = 8;
|
|
155
|
-
let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
|
|
156
155
|
|
|
157
156
|
// Cell renderer settings
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
let maxLengthOfMonomer: number = (_package.properties ? _package.properties.MaxMonomerLength : 4) ?? 50;
|
|
158
|
+
if (mmcrTAGS.maxMonomerLength in tableCol.tags) {
|
|
159
|
+
const v = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
|
|
160
|
+
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
161
|
+
}
|
|
162
|
+
if (Temps.maxMonomerLength in tableColTemp) {
|
|
163
|
+
const v = tableColTemp[Temps.maxMonomerLength];
|
|
164
|
+
maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
const [_gc, _tc, temp] =
|
|
169
168
|
getGridCellRendererBack<string, MonomerPlacer>(gridCell);
|
|
170
169
|
let seqColTemp: MonomerPlacer = temp.rendererBack;
|
|
171
170
|
if (!seqColTemp) {
|
|
172
|
-
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
|
|
171
|
+
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
|
|
173
172
|
() => {
|
|
174
173
|
const sh = SeqHandler.forColumn(tableCol);
|
|
175
174
|
return {
|
|
176
175
|
seqHandler: sh,
|
|
177
176
|
monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
|
|
178
|
-
monomerToShort: monomerToShortFunction,
|
|
177
|
+
monomerToShort: monomerToShortFunction,
|
|
179
178
|
};
|
|
180
179
|
});
|
|
181
180
|
}
|
|
182
181
|
|
|
183
182
|
g.save();
|
|
184
183
|
try {
|
|
185
|
-
if (
|
|
184
|
+
if (
|
|
185
|
+
tableCol.temp[Temps.rendererSettingsChanged] === rendererSettingsChangedState.true ||
|
|
186
|
+
seqColTemp.monomerLengthLimit != maxLengthOfMonomer
|
|
187
|
+
) {
|
|
186
188
|
gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
|
|
187
189
|
// this event means that the mm renderer settings have changed,
|
|
188
190
|
// particularly monomer representation and max width.
|
|
189
191
|
seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
|
|
190
192
|
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
191
|
-
tableCol.
|
|
193
|
+
tableCol.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.false;
|
|
192
194
|
}
|
|
193
195
|
|
|
194
196
|
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
@@ -245,9 +247,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
245
247
|
g.fillStyle = undefinedColor;
|
|
246
248
|
const last = posIdx === subParts.length - 1;
|
|
247
249
|
/*x1 = */
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
maxLengthWordsSum, posIdx, gridCell
|
|
250
|
+
const opts = {
|
|
251
|
+
color: color, pivot: 0, left: true, transparencyRate: 1.0, separator: separator, last: last,
|
|
252
|
+
drawStyle: drawStyle, maxWord: maxLengthWordsSum, wordIdx: posIdx, gridCell: gridCell,
|
|
253
|
+
referenceSequence: referenceSequence, maxLengthOfMonomer: maxLengthOfMonomer,
|
|
254
|
+
monomerTextSizeMap: seqColTemp._monomerLengthMap, logger: _package.logger
|
|
255
|
+
};
|
|
256
|
+
printLeftOrCentered(g, amino, x + this.padding, y, w, h, opts);
|
|
251
257
|
if (minDistanceRenderer > w) break;
|
|
252
258
|
}
|
|
253
259
|
} catch (err: any) {
|
|
@@ -350,14 +356,17 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
350
356
|
|
|
351
357
|
if (amino1 != amino2) {
|
|
352
358
|
const color2 = palette.get(amino2);
|
|
353
|
-
const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h,
|
|
354
|
-
|
|
359
|
+
const subX0 = printLeftOrCentered(g, amino1, updatedX, updatedY - vShift, w, h,
|
|
360
|
+
{color: color1, pivot: 0, left: true});
|
|
361
|
+
const subX1 = printLeftOrCentered(g, amino2, updatedX, updatedY + vShift, w, h,
|
|
362
|
+
{color: color2, pivot: 0, left: true});
|
|
355
363
|
updatedX = Math.max(subX1, subX0);
|
|
356
364
|
if (molDifferences)
|
|
357
365
|
molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
|
|
358
366
|
} else {
|
|
359
367
|
//
|
|
360
|
-
updatedX = printLeftOrCentered(
|
|
368
|
+
updatedX = printLeftOrCentered(g, amino1, updatedX, updatedY, w, h,
|
|
369
|
+
{color: color1, pivot: 0, left: true, transparencyRate: 0.5});
|
|
361
370
|
}
|
|
362
371
|
updatedX += 4;
|
|
363
372
|
}
|
|
@@ -382,8 +391,8 @@ function createDifferenceCanvas(amino1: string, amino2: string, color1: string,
|
|
|
382
391
|
canvas.width = width + 4;
|
|
383
392
|
context.font = '12px monospace';
|
|
384
393
|
context.textBaseline = 'top';
|
|
385
|
-
printLeftOrCentered(0, y - shift, width, h,
|
|
386
|
-
printLeftOrCentered(0, y + shift, width, h,
|
|
394
|
+
printLeftOrCentered(context, amino1, 0, y - shift, width, h, {color: color1, pivot: 0, left: true});
|
|
395
|
+
printLeftOrCentered(context, amino2, 0, y + shift, width, h, {color: color2, pivot: 0, left: true});
|
|
387
396
|
return canvas;
|
|
388
397
|
}
|
|
389
398
|
|
|
@@ -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;
|