@datagrok/bio 2.18.4 → 2.20.0
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 +5 -0
- package/README.md +2 -2
- package/dist/242.js +1 -1
- package/dist/242.js.map +1 -1
- package/dist/284.js +1 -1
- package/dist/284.js.map +1 -1
- package/dist/589.js +1 -1
- package/dist/589.js.map +1 -1
- package/dist/731.js +1 -1
- package/dist/731.js.map +1 -1
- package/dist/810.js +2 -0
- package/dist/810.js.map +1 -0
- package/dist/980.js +1 -1
- package/dist/980.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/dockerfiles/container.json +1 -1
- package/files/monomer-libraries/HELMCoreLibrary.json +18926 -18215
- package/files/samples/HELM_BI_CYCLIC.csv +7 -0
- package/files/samples/peptides-non-natural.csv +1001 -0
- package/files/tests/to-atomic-level-dna-fasta-output.csv +15077 -15077
- package/files/tests/to-atomic-level-msa-fasta-output.csv +1903 -1903
- package/files/tests/to-atomic-level-msa-separator-output.csv +3236 -3236
- package/files/tests/to-atomic-level-peptides-fasta-output.csv +32262 -32262
- package/files/tests/to-atomic-level-pt-fasta-2.mol +29 -29
- package/package.json +7 -7
- package/projects/seq_space_demo.zip +0 -0
- package/src/analysis/sequence-diversity-viewer.ts +22 -14
- package/src/analysis/sequence-search-base-viewer.ts +6 -72
- package/src/analysis/sequence-similarity-viewer.ts +42 -23
- package/src/demo/bio01-similarity-diversity.ts +21 -2
- package/src/demo/bio01a-hierarchical-clustering-and-sequence-space.ts +7 -0
- package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +1 -1
- package/src/demo/bio03-atomic-level.ts +15 -0
- package/src/package.ts +29 -59
- package/src/tests/activity-cliffs-utils.ts +7 -6
- package/src/tests/scoring.ts +2 -2
- package/src/tests/similarity-diversity-tests.ts +2 -2
- package/src/utils/cell-renderer.ts +11 -1
- package/src/utils/helm-to-molfile/converter/converter.ts +21 -9
- package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +8 -4
- package/src/utils/helm-to-molfile/converter/simple-polymer.ts +18 -9
- package/src/utils/monomer-lib/monomer-lib-base.ts +4 -4
- package/src/utils/pepsea.ts +22 -39
- package/src/utils/seq-helper/seq-handler.ts +2 -2
- package/src/utils/seq-helper/seq-helper.ts +50 -34
- package/src/utils/sequence-to-mol.ts +1 -1
- package/src/utils/ui-utils.ts +23 -0
- package/test-console-output-1.log +0 -7387
- package/test-record-1.mp4 +0 -0
package/src/package.ts
CHANGED
|
@@ -47,11 +47,10 @@ import {BioSubstructureFilter} from './widgets/bio-substructure-filter';
|
|
|
47
47
|
import {WebLogoViewer} from './viewers/web-logo-viewer';
|
|
48
48
|
import {MonomerLibManager} from './utils/monomer-lib/lib-manager';
|
|
49
49
|
import {getMonomerLibraryManagerLink, showManageLibrariesDialog, showManageLibrariesView} from './utils/monomer-lib/library-file-manager/ui';
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
50
|
+
import {demoBioSimDiv} from './demo/bio01-similarity-diversity';
|
|
51
|
+
import {demoSeqSpace} from './demo/bio01a-hierarchical-clustering-and-sequence-space';
|
|
52
52
|
import {demoBio01bUI} from './demo/bio01b-hierarchical-clustering-and-activity-cliffs';
|
|
53
|
-
import {
|
|
54
|
-
import {demoBio05UI} from './demo/bio05-helm-msa-sequence-space';
|
|
53
|
+
import {demoToAtomicLevel} from './demo/bio03-atomic-level';
|
|
55
54
|
import {checkInputColumnUI} from './utils/check-input-column';
|
|
56
55
|
import {MsaWarning} from './utils/multiple-sequence-alignment';
|
|
57
56
|
import {multipleSequenceAlignmentUI} from './utils/multiple-sequence-alignment-ui';
|
|
@@ -422,7 +421,7 @@ export function getRegion(
|
|
|
422
421
|
start ?? null, end ?? null, name ?? null);
|
|
423
422
|
}
|
|
424
423
|
|
|
425
|
-
//top-menu: Bio |
|
|
424
|
+
//top-menu: Bio | Calculate | Get Region...
|
|
426
425
|
//name: Get Region Top Menu
|
|
427
426
|
//description: Get sequences for a region specified from a Macromolecule
|
|
428
427
|
//input: dataframe table [Input data table]
|
|
@@ -587,7 +586,7 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, molecules: DG.Co
|
|
|
587
586
|
plotEmbeddings: boolean, preprocessingFunction?: DG.Func, options?: (IUMAPOptions | ITSNEOptions) & Options,
|
|
588
587
|
clusterEmbeddings?: boolean, isDemo?: boolean
|
|
589
588
|
): Promise<DG.ScatterPlotViewer | undefined> {
|
|
590
|
-
const tableView =
|
|
589
|
+
const tableView =
|
|
591
590
|
grok.shell.tv.dataFrame == table ? grok.shell.tv : undefined;
|
|
592
591
|
if (!checkInputColumnUI(molecules, 'Sequence Space'))
|
|
593
592
|
return;
|
|
@@ -607,14 +606,13 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, molecules: DG.Co
|
|
|
607
606
|
return res;
|
|
608
607
|
}
|
|
609
608
|
|
|
610
|
-
//top-menu: Bio |
|
|
609
|
+
//top-menu: Bio | Transform | To Atomic Level...
|
|
611
610
|
//name: To Atomic Level
|
|
612
611
|
//description: Converts sequences to molblocks
|
|
613
612
|
//input: dataframe table [Input data table]
|
|
614
613
|
//input: column seqCol {caption: Sequence; semType: Macromolecule}
|
|
615
614
|
//input: bool nonlinear =false {caption: Non-linear; description: Slower mode for cycling/branching HELM structures}
|
|
616
615
|
//input: bool highlight =false {caption: Highlight monomers; description: Highlight monomers' substructures of the molecule }
|
|
617
|
-
//output:
|
|
618
616
|
export async function toAtomicLevel(
|
|
619
617
|
table: DG.DataFrame, seqCol: DG.Column, nonlinear: boolean, highlight: boolean = false
|
|
620
618
|
): Promise<void> {
|
|
@@ -630,6 +628,17 @@ export async function toAtomicLevel(
|
|
|
630
628
|
}
|
|
631
629
|
}
|
|
632
630
|
|
|
631
|
+
//name: To Atomic Level...
|
|
632
|
+
//input: column seqCol {semType: Macromolecule}
|
|
633
|
+
//meta.action: to atomic level
|
|
634
|
+
export async function toAtomicLevelAction(seqCol: DG.Column) {
|
|
635
|
+
if (!seqCol?.dataFrame)
|
|
636
|
+
throw new Error('Sequence column is not found or its data frame is not empty');
|
|
637
|
+
const func = DG.Func.find({name: 'toAtomicLevel', package: 'Bio'})[0];
|
|
638
|
+
if (!func) throw new Error('To Atomic level Function not found');
|
|
639
|
+
func.prepare({table: seqCol.dataFrame, seqCol: seqCol}).edit();
|
|
640
|
+
}
|
|
641
|
+
|
|
633
642
|
//top-menu: Bio | Analyze | MSA...
|
|
634
643
|
//name: MSA
|
|
635
644
|
//description: Performs multiple sequence alignment
|
|
@@ -743,38 +752,20 @@ export function importBam(fileContent: string): DG.DataFrame [] {
|
|
|
743
752
|
return [];
|
|
744
753
|
}
|
|
745
754
|
|
|
746
|
-
//top-menu: Bio |
|
|
755
|
+
//top-menu: Bio | Transform | Convert Notation...
|
|
747
756
|
//name: convertDialog
|
|
748
757
|
export function convertDialog() {
|
|
749
758
|
const col: DG.Column<string> | undefined = getMacromoleculeColumns()[0];
|
|
750
759
|
convert(col, _package.seqHelper);
|
|
751
760
|
}
|
|
752
761
|
|
|
753
|
-
//
|
|
754
|
-
//
|
|
755
|
-
//
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
//input: string separator
|
|
759
|
-
//output: string result
|
|
760
|
-
export async function convertSeqNotation(sequence: string, targetNotation: NOTATION, separator?: string): Promise<string | undefined | null> {
|
|
761
|
-
try {
|
|
762
|
-
const col = DG.Column.fromStrings('sequence', [sequence]);
|
|
763
|
-
const _df = DG.DataFrame.fromColumns([col]);
|
|
764
|
-
const semType = await grok.functions.call('Bio:detectMacromolecule', {col: col});
|
|
765
|
-
if (semType)
|
|
766
|
-
col.semType = semType;
|
|
767
|
-
const converterSh = _package.seqHelper.getSeqHandler(col);
|
|
768
|
-
const newColumn = converterSh.convert(targetNotation, separator);
|
|
769
|
-
return newColumn.get(0);
|
|
770
|
-
} catch (err: any) {
|
|
771
|
-
const [errMsg, errStack] = errInfo(err);
|
|
772
|
-
_package.logger.error(errMsg, undefined, errStack);
|
|
773
|
-
throw err;
|
|
774
|
-
}
|
|
762
|
+
//name: Convert Notation...
|
|
763
|
+
//input: column col {semType: Macromolecule}
|
|
764
|
+
//meta.action: Convert Notation...
|
|
765
|
+
export function convertColumnAction(col: DG.Column) {
|
|
766
|
+
convert(col, _package.seqHelper);
|
|
775
767
|
}
|
|
776
768
|
|
|
777
|
-
|
|
778
769
|
//name: monomerCellRenderer
|
|
779
770
|
//tags: cellRenderer
|
|
780
771
|
//meta.cellType: Monomer
|
|
@@ -835,7 +826,7 @@ export async function testDetectMacromolecule(path: string): Promise<DG.DataFram
|
|
|
835
826
|
return resDf;
|
|
836
827
|
}
|
|
837
828
|
|
|
838
|
-
//top-menu: Bio |
|
|
829
|
+
//top-menu: Bio | Transform | Split to Monomers...
|
|
839
830
|
//name: Split to Monomers
|
|
840
831
|
//input: dataframe table
|
|
841
832
|
//input: column sequence { semType: Macromolecule }
|
|
@@ -975,21 +966,14 @@ export async function manageLibrariesApp(): Promise<DG.View> {
|
|
|
975
966
|
|
|
976
967
|
//name: Monomer Manager Tree Browser
|
|
977
968
|
//input: dynamic treeNode
|
|
978
|
-
//input:
|
|
979
|
-
export async function manageLibrariesAppTreeBrowser(treeNode: DG.TreeViewGroup,
|
|
969
|
+
//input: dynamic browsePanel
|
|
970
|
+
export async function manageLibrariesAppTreeBrowser(treeNode: DG.TreeViewGroup, browsePanel: DG.BrowsePanel) {
|
|
980
971
|
const libraries = (await (await MonomerLibManager.getInstance()).getFileManager()).getValidLibraryPaths();
|
|
981
972
|
libraries.forEach((libName) => {
|
|
982
973
|
const nodeName = libName.endsWith('.json') ? libName.substring(0, libName.length - 5) : libName;
|
|
983
974
|
const libNode = treeNode.item(nodeName);
|
|
984
975
|
// eslint-disable-next-line rxjs/no-ignored-subscription, rxjs/no-async-subscribe
|
|
985
976
|
libNode.onSelected.subscribe(async () => {
|
|
986
|
-
const monomerManager = await MonomerManager.getNewInstance();
|
|
987
|
-
browseView.preview = await monomerManager.getViewRoot(libName, false);
|
|
988
|
-
});
|
|
989
|
-
|
|
990
|
-
libNode.root.addEventListener('dblclick', async (e) => {
|
|
991
|
-
e.preventDefault();
|
|
992
|
-
e.stopImmediatePropagation();
|
|
993
977
|
const monomerManager = await MonomerManager.getInstance();
|
|
994
978
|
await monomerManager.getViewRoot(libName, true);
|
|
995
979
|
monomerManager.resetCurrentRowFollowing();
|
|
@@ -1111,10 +1095,9 @@ export function addCopyMenu(cell: DG.Cell, menu: DG.Menu): void {
|
|
|
1111
1095
|
//meta.demoPath: Bioinformatics | Similarity, Diversity
|
|
1112
1096
|
//description: Sequence similarity tracking and evaluation dataset diversity
|
|
1113
1097
|
//meta.path: /apps/Tutorials/Demo/Bioinformatics/Similarity,%20Diversity
|
|
1114
|
-
//meta.isDemoScript: True
|
|
1115
1098
|
//meta.demoSkip: GROK-14320
|
|
1116
1099
|
export async function demoBioSimilarityDiversity(): Promise<void> {
|
|
1117
|
-
await
|
|
1100
|
+
await demoBioSimDiv();
|
|
1118
1101
|
}
|
|
1119
1102
|
|
|
1120
1103
|
// demoBio01a
|
|
@@ -1122,10 +1105,9 @@ export async function demoBioSimilarityDiversity(): Promise<void> {
|
|
|
1122
1105
|
//meta.demoPath: Bioinformatics | Sequence Space
|
|
1123
1106
|
//description: Exploring sequence space of Macromolecules, comparison with hierarchical clustering results
|
|
1124
1107
|
//meta.path: /apps/Tutorials/Demo/Bioinformatics/Sequence%20Space
|
|
1125
|
-
//meta.isDemoScript: True
|
|
1126
1108
|
//meta.demoSkip: GROK-14320
|
|
1127
1109
|
export async function demoBioSequenceSpace(): Promise<void> {
|
|
1128
|
-
await
|
|
1110
|
+
await demoSeqSpace();
|
|
1129
1111
|
}
|
|
1130
1112
|
|
|
1131
1113
|
// demoBio01b
|
|
@@ -1144,21 +1126,9 @@ export async function demoBioActivityCliffs(): Promise<void> {
|
|
|
1144
1126
|
//meta.demoPath: Bioinformatics | Atomic Level
|
|
1145
1127
|
//description: Atomic level structure of Macromolecules
|
|
1146
1128
|
//meta.path: /apps/Tutorials/Demo/Bioinformatics/Atomic%20Level
|
|
1147
|
-
//meta.isDemoScript: True
|
|
1148
1129
|
//meta.demoSkip: GROK-14320
|
|
1149
1130
|
export async function demoBioAtomicLevel(): Promise<void> {
|
|
1150
|
-
await
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
// demoBio05
|
|
1154
|
-
//name: demoBioHelmMsaSequenceSpace
|
|
1155
|
-
//meta.demoPath: Bioinformatics | Helm, MSA, Sequence Space
|
|
1156
|
-
//description: MSA and composition analysis on Helm data
|
|
1157
|
-
//meta.path: /apps/Tutorials/Demo/Bioinformatics/Helm,%20MSA,%20Sequence%20Space
|
|
1158
|
-
//meta.isDemoScript: True
|
|
1159
|
-
//meta.demoSkip: GROK-14320
|
|
1160
|
-
export async function demoBioHelmMsaSequenceSpace(): Promise<void> {
|
|
1161
|
-
await demoBio05UI();
|
|
1131
|
+
await demoToAtomicLevel();
|
|
1162
1132
|
}
|
|
1163
1133
|
|
|
1164
1134
|
//name: SDF to JSON Library
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
|
|
4
|
-
import {expect} from '@datagrok-libraries/utils/src/test';
|
|
4
|
+
import {awaitCheck, expect} from '@datagrok-libraries/utils/src/test';
|
|
5
5
|
import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule-distance-functions';
|
|
6
6
|
import {BitArrayMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
7
7
|
import {BYPASS_LARGE_DATA_WARNING} from '@datagrok-libraries/ml/src/functionEditors/consts';
|
|
@@ -25,9 +25,10 @@ export async function _testActivityCliffsOpen(df: DG.DataFrame, drMethod: DimRed
|
|
|
25
25
|
})) as DG.Viewer | undefined;
|
|
26
26
|
expect(scatterPlot != null, true);
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
await awaitCheck(() => {
|
|
29
|
+
const link = Array.from(scatterPlot!.root.getElementsByClassName('scatter_plot_link'));
|
|
30
|
+
if (link.length)
|
|
31
|
+
return (link[0] as HTMLElement).innerText.toLowerCase() === `${tgtNumberCliffs} cliffs`;
|
|
32
|
+
return true;
|
|
33
|
+
}, 'incorrect cliffs link', 3000);
|
|
33
34
|
}
|
package/src/tests/scoring.ts
CHANGED
|
@@ -21,8 +21,8 @@ category('Scoring', () => {
|
|
|
21
21
|
/* eslint-disable max-len */
|
|
22
22
|
const table = DG.DataFrame.fromCsv(`${sequence},${expectedSimilarity},${expectedIdentity}
|
|
23
23
|
PEPTIDE1{Aca.Orn.gGlu.Pqa.D-His_1Bn.dH.hHis.4Abz.D-Tic.D-Dap.Y.Iva.meS.F.P.F.D-1Nal}$$$$,1.0,1.0
|
|
24
|
-
PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC}$$$$,0.
|
|
25
|
-
PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal]}$$$$V2.0,0.
|
|
24
|
+
PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC}$$$$,0.691,0.53
|
|
25
|
+
PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal]}$$$$V2.0,0.37,0.0`
|
|
26
26
|
);
|
|
27
27
|
const seqCol: DG.Column<string> = table.getCol(sequence);
|
|
28
28
|
seqCol.meta.units = NOTATION.HELM;
|
|
@@ -37,7 +37,7 @@ async function _testSimilaritySearchViewer() {
|
|
|
37
37
|
await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Similarity Search') !== undefined,
|
|
38
38
|
'Sequence Similarity Search viewer has not been created', 100);
|
|
39
39
|
if (!viewer.initialized) throw new Error('The viewer is not initialized.');
|
|
40
|
-
if (!viewer.
|
|
40
|
+
if (!viewer.targetColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
|
|
41
41
|
if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
|
|
42
42
|
if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
|
|
43
43
|
if (!computeCompleted) throw new Error('The viewer has not compute completed.');
|
|
@@ -87,7 +87,7 @@ async function _testDiversitySearchViewer() {
|
|
|
87
87
|
await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Diversity Search') !== undefined,
|
|
88
88
|
'Sequence Diversity Search viewer has not been created', 100);
|
|
89
89
|
if (!viewer.initialized) throw new Error('The viewer is not initialized.');
|
|
90
|
-
if (!viewer.
|
|
90
|
+
if (!viewer.targetColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
|
|
91
91
|
if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
|
|
92
92
|
if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
|
|
93
93
|
if (!computeCompleted) throw new Error('The viewer has not compute completed.');
|
|
@@ -58,7 +58,6 @@ export function processSequence(subParts: string[]): [string[], boolean] {
|
|
|
58
58
|
type RendererGridCellTemp = {
|
|
59
59
|
[MmcrTemps.monomerPlacer]: MonomerPlacer
|
|
60
60
|
}
|
|
61
|
-
|
|
62
61
|
export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
63
62
|
private readonly seqHelper: ISeqHelper;
|
|
64
63
|
|
|
@@ -70,6 +69,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
70
69
|
|
|
71
70
|
get defaultWidth(): number | null { return 230; }
|
|
72
71
|
|
|
72
|
+
hasMouseOver: boolean = false;
|
|
73
|
+
|
|
73
74
|
constructor() {
|
|
74
75
|
super();
|
|
75
76
|
this.seqHelper = _package.seqHelper;
|
|
@@ -101,6 +102,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
101
102
|
override onMouseEnter(gridCell: DG.GridCell, e: MouseEvent) {
|
|
102
103
|
const back = this.getRendererBack(gridCell);
|
|
103
104
|
back?.onMouseEnter(gridCell, e);
|
|
105
|
+
this.hasMouseOver = true;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
override onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
@@ -110,6 +112,14 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
110
112
|
|
|
111
113
|
override onMouseLeave(gridCell: DG.GridCell, _e: MouseEvent) {
|
|
112
114
|
execMonomerHoverLinks(gridCell, null);
|
|
115
|
+
if (gridCell?.grid) {
|
|
116
|
+
const sub = gridCell.grid.onEvent('d4-grid-show-tooltip').subscribe((e) => {
|
|
117
|
+
sub.unsubscribe();
|
|
118
|
+
if (this.hasMouseOver)
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
this.hasMouseOver = false;
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
override onDoubleClick(gridCell: DG.GridCell, e: MouseEvent) {
|
|
@@ -4,9 +4,8 @@ import * as OCL from 'openchemlib/full';
|
|
|
4
4
|
|
|
5
5
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
6
6
|
import {RDModule, RDMol} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
7
|
+
import {IMonomerLibBase} from '@datagrok-libraries/bio/src/types/index';
|
|
8
|
+
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
10
9
|
import {MolfileWithMap, MonomerMap} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
11
10
|
|
|
12
11
|
import {Polymer} from './polymer';
|
|
@@ -14,9 +13,10 @@ import {GlobalMonomerPositionHandler} from './position-handler';
|
|
|
14
13
|
|
|
15
14
|
import {_package} from '../../../package';
|
|
16
15
|
import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
|
|
16
|
+
import {IHelmToMolfileConverter} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
export class HelmToMolfileConverter {
|
|
19
|
+
export class HelmToMolfileConverter implements IHelmToMolfileConverter {
|
|
20
20
|
constructor(
|
|
21
21
|
private readonly helmHelper: IHelmHelper,
|
|
22
22
|
private readonly rdKitModule: RDModule,
|
|
@@ -41,6 +41,20 @@ export class HelmToMolfileConverter {
|
|
|
41
41
|
return smiles;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
public molV3KtoMolV3KOCL(molV3k: string): string {
|
|
45
|
+
try {
|
|
46
|
+
if (!molV3k)
|
|
47
|
+
return '';
|
|
48
|
+
const oclMolecule = OCL.Molecule.fromMolfile(molV3k);
|
|
49
|
+
const molV3000 = oclMolecule.toMolfileV3();
|
|
50
|
+
return molV3000.replace('STERAC1', 'STEABS');
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const [errMsg, errStack] = errInfo(err);
|
|
53
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
public getMolV3000ViaOCL(beautifiedMols: (RDMol | null)[], columnName: string): DG.Column<string> {
|
|
45
59
|
const beautifiedMolV2000 = beautifiedMols.map((mol) => {
|
|
46
60
|
if (mol === null)
|
|
@@ -52,9 +66,7 @@ export class HelmToMolfileConverter {
|
|
|
52
66
|
const molv3000Arr = new Array<string>(beautifiedMolV2000.length);
|
|
53
67
|
const chiralityPb = DG.TaskBarProgressIndicator.create(`Handling chirality...`);
|
|
54
68
|
for (let i = 0; i < beautifiedMolV2000.length; i++) {
|
|
55
|
-
|
|
56
|
-
const molV3000 = oclMolecule.toMolfileV3();
|
|
57
|
-
molv3000Arr[i] = molV3000.replace('STERAC1', 'STEABS');
|
|
69
|
+
molv3000Arr[i] = this.molV3KtoMolV3KOCL(beautifiedMolV2000[i]);
|
|
58
70
|
const progress = i / beautifiedMolV2000.length * 100;
|
|
59
71
|
chiralityPb.update(progress, `${progress?.toFixed(2)}% of molecules completed`);
|
|
60
72
|
}
|
|
@@ -136,9 +148,9 @@ export class HelmToMolfileConverter {
|
|
|
136
148
|
const woGapsRes = this.helmHelper.removeGaps(helm);
|
|
137
149
|
const woGapsHelm = woGapsRes.resHelm;
|
|
138
150
|
const woGapsReverseMap = new Map<number, number>();
|
|
139
|
-
for (const [orgPosIdx, woGapsPosIdx] of (woGapsRes.monomerMap?.entries() ?? []))
|
|
151
|
+
for (const [orgPosIdx, woGapsPosIdx] of (woGapsRes.monomerMap?.entries() ?? []))
|
|
140
152
|
woGapsReverseMap.set(woGapsPosIdx, orgPosIdx);
|
|
141
|
-
|
|
153
|
+
|
|
142
154
|
const pseudoMolfile = this.helmHelper.getMolfiles([woGapsHelm])[0];
|
|
143
155
|
const globalPositionHandler = new GlobalMonomerPositionHandler(pseudoMolfile);
|
|
144
156
|
const woGapsPolymer = new Polymer(woGapsHelm, this.rdKitModule, this.monomerLib);
|
|
@@ -10,7 +10,7 @@ import {MolfileWrapperFactory} from './mol-wrapper-factory';
|
|
|
10
10
|
export class MonomerWrapper {
|
|
11
11
|
private readonly molfileWrapper: MolfileWrapper;
|
|
12
12
|
private capGroupElements: string[] = [];
|
|
13
|
-
|
|
13
|
+
private static molfileV2KToV3KCache: Map<string, string> = new Map();
|
|
14
14
|
constructor(
|
|
15
15
|
public readonly monomerSymbol: string,
|
|
16
16
|
public readonly monomerIdx: number,
|
|
@@ -39,12 +39,16 @@ export class MonomerWrapper {
|
|
|
39
39
|
public get bondCount() { return this.molfileWrapper.bondCount; }
|
|
40
40
|
|
|
41
41
|
private convertMolfileToV3KFormat(molfileV2K: string, monomerSymbol: string, rdKitModule: RDModule): string {
|
|
42
|
+
if (MonomerWrapper.molfileV2KToV3KCache.has(molfileV2K))
|
|
43
|
+
return MonomerWrapper.molfileV2KToV3KCache.get(molfileV2K)!;
|
|
42
44
|
let mol: RDMol | null = null;
|
|
43
45
|
try {
|
|
44
46
|
mol = rdKitModule.get_mol(molfileV2K, JSON.stringify({mergeQueryHs: true}));
|
|
45
|
-
if (mol)
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
if (mol) {
|
|
48
|
+
const res = mol.get_v3Kmolblock();
|
|
49
|
+
MonomerWrapper.molfileV2KToV3KCache.set(molfileV2K, res);
|
|
50
|
+
return res;
|
|
51
|
+
} else
|
|
48
52
|
throw new Error(`Cannot convert ${monomerSymbol} to molV3000`);
|
|
49
53
|
} finally {
|
|
50
54
|
mol?.delete();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
1
2
|
import {HELM_MONOMER_TYPE, HELM_POLYMER_TYPE} from '@datagrok-libraries/bio/src/utils/const';
|
|
2
3
|
import {cleanupHelmSymbol} from '@datagrok-libraries/bio/src/helm/utils';
|
|
3
4
|
|
|
@@ -5,8 +6,10 @@ import {Bond} from './types';
|
|
|
5
6
|
|
|
6
7
|
/** Wrapper over simple polymer substring of HELM, like RNA1{d(A)p} */
|
|
7
8
|
export class SimplePolymer {
|
|
9
|
+
private isNucleotideSequence = false;
|
|
8
10
|
constructor(private simplePolymer: string) {
|
|
9
11
|
this.polymerType = this.getPolymerType();
|
|
12
|
+
this.isNucleotideSequence = this.polymerType === HELM_POLYMER_TYPE.RNA;
|
|
10
13
|
this.idx = this.getIdx();
|
|
11
14
|
const {monomers, monomerTypes} = this.getMonomerSymbolsAndTypes();
|
|
12
15
|
this.monomers = monomers;
|
|
@@ -49,17 +52,23 @@ export class SimplePolymer {
|
|
|
49
52
|
const monomerList: string[] = [];
|
|
50
53
|
const monomerTypeList: HELM_MONOMER_TYPE[] = [];
|
|
51
54
|
monomerGroups.forEach((monomerGroup) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
if (!this.isNucleotideSequence) {
|
|
56
|
+
// const splitted = monomerGroup.split(/\(|\)/).map((el) => el.replace(/[\[\]]/g, ''));
|
|
57
|
+
// monomerList.push(...splitted);
|
|
58
|
+
// WARNING: only the groups of the form r(A)p, as in RNA, are supported
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
monomerList.push(cleanupHelmSymbol(monomerGroup));
|
|
61
|
+
// const monomerTypes = splitted.map(
|
|
62
|
+
// (_, idx) => (idx % 2 === 0) ? HELM_MONOMER_TYPE.BACKBONE : HELM_MONOMER_TYPE.BRANCH
|
|
63
|
+
// );
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
// monomerTypeList.push(...monomerTypes);
|
|
66
|
+
monomerTypeList.push(HELM_MONOMER_TYPE.BACKBONE);
|
|
67
|
+
} else {
|
|
68
|
+
const splitted = monomerGroup.split(/\(|\)/).filter((el) => !!el).map((el) => cleanupHelmSymbol(el));
|
|
69
|
+
monomerList.push(...splitted);
|
|
70
|
+
splitted.forEach((_, i) => monomerTypeList.push(i % 3 === 1 ? HELM_MONOMER_TYPE.BRANCH : HELM_MONOMER_TYPE.BACKBONE));
|
|
71
|
+
}
|
|
63
72
|
});
|
|
64
73
|
return {monomers: monomerList, monomerTypes: monomerTypeList};
|
|
65
74
|
}
|
|
@@ -177,13 +177,13 @@ export class MonomerLibBase implements IMonomerLibBase {
|
|
|
177
177
|
// Symbol & Name
|
|
178
178
|
const symbol = monomer[REQ.SYMBOL];
|
|
179
179
|
const _name = monomer[REQ.NAME];
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
const [color, backgroundColor, lineColor] =
|
|
181
|
+
wem ? [wem.textcolor, wem.backgroundcolor, wem.linecolor] : ['#202020', '#A0A0A0', '#202020'];
|
|
182
182
|
res.append(ui.divH([
|
|
183
183
|
ui.div([symbol], {
|
|
184
184
|
style: {
|
|
185
185
|
/* fontWeight: 'bolder', */ textWrap: 'nowrap', marginLeft: '4px', marginRight: '4px',
|
|
186
|
-
color:
|
|
186
|
+
color: color, backgroundColor: backgroundColor, borderColor: lineColor,
|
|
187
187
|
borderWidth: '1px', borderStyle: 'solid', borderRadius: '2px', padding: '3px',
|
|
188
188
|
minWidth: '24px', textAlign: 'center',
|
|
189
189
|
}
|
|
@@ -192,7 +192,7 @@ export class MonomerLibBase implements IMonomerLibBase {
|
|
|
192
192
|
], {style: {display: 'flex', flexDirection: 'row', justifyContent: 'left'}}));
|
|
193
193
|
|
|
194
194
|
// Structure
|
|
195
|
-
const chemOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
195
|
+
//const chemOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
196
196
|
let structureEl: HTMLElement;
|
|
197
197
|
if (monomer.molfile)
|
|
198
198
|
structureEl = drawMoleculeCall(monomer.molfile);
|
package/src/utils/pepsea.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {Subject} from 'rxjs';
|
|
|
7
7
|
|
|
8
8
|
import {testEvent} from '@datagrok-libraries/utils/src/test';
|
|
9
9
|
import {NOTATION, TAGS as bioTAGS, ALIGNMENT, ALPHABET} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
|
-
import {
|
|
10
|
+
import {fetchWrapper} from '@datagrok-libraries/utils/src/fetch-utils';
|
|
11
11
|
import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
|
|
12
12
|
|
|
13
13
|
import {checkForSingleSeqClusters} from './multiple-sequence-alignment';
|
|
@@ -108,50 +108,33 @@ async function requestAlignedObjects(
|
|
|
108
108
|
body: JSON.stringify(body),
|
|
109
109
|
};
|
|
110
110
|
const path = `/align?method=${method}&gap_open=${gapOpen}&gap_extend=${gapExtend}`;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
const responseJson = await response.json();
|
|
123
|
-
const pepseaErrorMsg = responseJson['pepsea-error'];
|
|
124
|
-
if (!!pepseaErrorMsg)
|
|
125
|
-
throw new Error(`PepSeA error: ${pepseaErrorMsg}`);
|
|
126
|
-
|
|
127
|
-
const datagrokErrorMsg = responseJson['datagrok-error'];
|
|
128
|
-
if (!!datagrokErrorMsg)
|
|
129
|
-
throw new Error(`Datagrok error: ${datagrokErrorMsg}`);
|
|
130
|
-
|
|
131
|
-
throw new Error(response.statusText);
|
|
132
|
-
} else if (!response.ok && !isJson) {
|
|
133
|
-
const responseStr = await response.text();
|
|
134
|
-
throw new Error(`Error: ${responseStr}`);
|
|
135
|
-
} else if (!isJson) {
|
|
136
|
-
const responseStr = await response.text();
|
|
137
|
-
throw new Error(`Error: PepSeA expected JSON response, got '${responseStr}'.`);
|
|
138
|
-
}
|
|
139
|
-
responseObj = await response.json();
|
|
140
|
-
} else {
|
|
141
|
-
// @ts-ignore
|
|
142
|
-
const responseStr = await grok.dapi.docker.dockerContainers.request(dockerfileId, path, params)!;
|
|
143
|
-
if (!responseStr)
|
|
144
|
-
throw new Error('Empty response');
|
|
145
|
-
responseObj = JSON.parse(responseStr);
|
|
146
|
-
|
|
147
|
-
const pepseaErrorMsg = responseObj['pepsea-error'];
|
|
111
|
+
// new dockerContainers API
|
|
112
|
+
const t1: number = window.performance.now();
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
const response: Response = await grok.dapi.docker.dockerContainers.fetchProxy(dockerfileId, path, params);
|
|
115
|
+
const t2: number = window.performance.now();
|
|
116
|
+
_package.logger.debug(`Bio: requestAlignedObjects() dockerContainers.fetchProxy(), ET: ${(t2 - t1)} ms`);
|
|
117
|
+
const responseContentType = response.headers.get('content-type');
|
|
118
|
+
const isJson: boolean = responseContentType === 'application/json';
|
|
119
|
+
if (!response.ok && isJson) {
|
|
120
|
+
const responseJson = await response.json();
|
|
121
|
+
const pepseaErrorMsg = responseJson['pepsea-error'];
|
|
148
122
|
if (!!pepseaErrorMsg)
|
|
149
123
|
throw new Error(`PepSeA error: ${pepseaErrorMsg}`);
|
|
150
124
|
|
|
151
|
-
const datagrokErrorMsg =
|
|
125
|
+
const datagrokErrorMsg = responseJson['datagrok-error'];
|
|
152
126
|
if (!!datagrokErrorMsg)
|
|
153
127
|
throw new Error(`Datagrok error: ${datagrokErrorMsg}`);
|
|
128
|
+
|
|
129
|
+
throw new Error(response.statusText);
|
|
130
|
+
} else if (!response.ok && !isJson) {
|
|
131
|
+
const responseStr = await response.text();
|
|
132
|
+
throw new Error(`Error: ${responseStr}`);
|
|
133
|
+
} else if (!isJson) {
|
|
134
|
+
const responseStr = await response.text();
|
|
135
|
+
throw new Error(`Error: PepSeA expected JSON response, got '${responseStr}'.`);
|
|
154
136
|
}
|
|
137
|
+
const responseObj = await response.json();
|
|
155
138
|
// Check for pepsea stderr output
|
|
156
139
|
if ('pepsea-stderr' in responseObj) {
|
|
157
140
|
const pepseaStdErr: string = responseObj['pepsea-stderr'] as string;
|
|
@@ -605,12 +605,12 @@ export class SeqHandler implements ISeqHandler {
|
|
|
605
605
|
|
|
606
606
|
const isNucleotide = srcSeq.startsWith('RNA');
|
|
607
607
|
// items can be monomers or helms
|
|
608
|
-
const helmItemsArray =
|
|
608
|
+
const helmItemsArray = splitterAsHelm(srcSeq);
|
|
609
609
|
const tgtMonomersArray: string[] = [];
|
|
610
610
|
for (let posIdx = 0; posIdx < helmItemsArray.length; ++posIdx) {
|
|
611
611
|
let om: string = helmItemsArray.getOriginal(posIdx);
|
|
612
612
|
if (isNucleotide)
|
|
613
|
-
om = om.replace(HELM_WRAPPERS_REGEXP, '');
|
|
613
|
+
om = om.replace(HELM_WRAPPERS_REGEXP, '$1');
|
|
614
614
|
if (om === GapOriginals[NOTATION.HELM])
|
|
615
615
|
tgtMonomersArray.push(tgtGapOriginal);
|
|
616
616
|
else if (this.toFasta(tgtNotation as NOTATION) && om.length > 1) {
|