@datagrok/bio 2.20.0 → 2.20.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/CHANGELOG.md +10 -0
- package/detectors.js +10 -6
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/tests/helm_cyclic_cliffs.csv +225019 -0
- package/package.json +1 -1
- package/src/analysis/sequence-search-base-viewer.ts +1 -1
- package/src/analysis/sequence-similarity-viewer.ts +1 -20
- package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +37 -0
- package/src/package.ts +12 -3
- package/src/widgets/to-atomic-level-widget.ts +79 -0
- package/test-console-output-1.log +7361 -0
- package/test-record-1.mp4 +0 -0
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.20.
|
|
8
|
+
"version": "2.20.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,7 +13,7 @@ export class SequenceSearchBaseViewer extends SearchBaseViewer {
|
|
|
13
13
|
fingerprint: string;
|
|
14
14
|
metricsProperties = ['distanceMetric', 'fingerprint'];
|
|
15
15
|
fingerprintChoices = ['Morgan', 'Pattern'];
|
|
16
|
-
tags = [DG.TAGS.UNITS, bioTAGS.aligned, bioTAGS.separator, bioTAGS.alphabet];
|
|
16
|
+
tags = [DG.TAGS.UNITS, bioTAGS.aligned, bioTAGS.separator, bioTAGS.alphabet, 'cell.renderer'];
|
|
17
17
|
preComputeDistanceMatrix: boolean = false;
|
|
18
18
|
|
|
19
19
|
constructor(name: string, semType: string) {
|
|
@@ -3,7 +3,6 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import {SequenceSearchBaseViewer} from './sequence-search-base-viewer';
|
|
6
|
-
import {getMonomericMols} from '../calculations/monomerLevelMols';
|
|
7
6
|
import {createDifferenceCanvas, createDifferencesWithPositions} from './sequence-activity-cliffs';
|
|
8
7
|
import {adjustGridcolAfterRender, updateDivInnerHTML} from '../utils/ui-utils';
|
|
9
8
|
import {Subject} from 'rxjs';
|
|
@@ -57,8 +56,7 @@ export class SequenceSimilarityViewer extends SequenceSearchBaseViewer {
|
|
|
57
56
|
if (this.targetColumn) {
|
|
58
57
|
this.curIdx = this.dataFrame!.currentRowIdx == -1 ? 0 : this.dataFrame!.currentRowIdx;
|
|
59
58
|
if (computeData && !this.gridSelect) {
|
|
60
|
-
this.targetMoleculeIdx = this.dataFrame!.currentRowIdx
|
|
61
|
-
const sh = this.seqHelper.getSeqHandler(this.targetColumn!);
|
|
59
|
+
this.targetMoleculeIdx = (this.dataFrame!.currentRowIdx ?? -1) < 0 ? 0 : this.dataFrame!.currentRowIdx;
|
|
62
60
|
|
|
63
61
|
await this.computeByMM();
|
|
64
62
|
const similarColumnName: string = this.similarColumnLabel != null ? this.similarColumnLabel :
|
|
@@ -103,23 +101,6 @@ export class SequenceSimilarityViewer extends SequenceSearchBaseViewer {
|
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
private async computeByChem() {
|
|
107
|
-
const monomericMols = await getMonomericMols(this.targetColumn!, this.seqHelper);
|
|
108
|
-
//need to create df to calculate fingerprints
|
|
109
|
-
const _monomericMolsDf = DG.DataFrame.fromColumns([monomericMols]);
|
|
110
|
-
const df = await grok.functions.call('Chem:callChemSimilaritySearch', {
|
|
111
|
-
df: this.dataFrame,
|
|
112
|
-
col: monomericMols,
|
|
113
|
-
molecule: monomericMols.get(this.targetMoleculeIdx),
|
|
114
|
-
metricName: this.distanceMetric,
|
|
115
|
-
limit: this.limit,
|
|
116
|
-
minScore: this.cutoff,
|
|
117
|
-
fingerprint: this.fingerprint,
|
|
118
|
-
});
|
|
119
|
-
this.idxs = df.getCol('indexes');
|
|
120
|
-
this.scores = df.getCol('score');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
104
|
private async computeByMM() {
|
|
124
105
|
const len = this.targetColumn!.length;
|
|
125
106
|
const actualLimit = Math.min(this.limit, len - 1);
|
|
@@ -107,3 +107,40 @@ export async function demoBio01bUI() {
|
|
|
107
107
|
handleError(err);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
|
|
111
|
+
export async function demoActivityCliffsCyclic() {
|
|
112
|
+
const df = await _package.files.readCsv('tests/helm_cyclic_cliffs.csv');
|
|
113
|
+
df.name = 'Activity Cliffs Demo';
|
|
114
|
+
await grok.data.detectSemanticTypes(df);
|
|
115
|
+
await df.meta.detectSemanticTypes();
|
|
116
|
+
const tv = grok.shell.addTableView(df);
|
|
117
|
+
ui.setUpdateIndicator(tv.root, true);
|
|
118
|
+
try {
|
|
119
|
+
const seqEncodingFunc = DG.Func.find({name: 'macromoleculePreprocessingFunction', package: 'Bio'})[0];
|
|
120
|
+
const activityCliffsViewer = (await activityCliffs(
|
|
121
|
+
df, df.getCol('Sequence'), df.getCol('Activity'),
|
|
122
|
+
96, DimReductionMethods.UMAP, MmDistanceFunctionsNames.MONOMER_CHEMICAL_DISTANCE,
|
|
123
|
+
seqEncodingFunc, {}, true)) as DG.ScatterPlotViewer;
|
|
124
|
+
tv.dockManager.dock(activityCliffsViewer, DG.DOCK_TYPE.RIGHT, null, 'Activity Cliffs', 0.65);
|
|
125
|
+
await DG.delay(100);
|
|
126
|
+
const cliffsLink: HTMLButtonElement = $(activityCliffsViewer.root)
|
|
127
|
+
.find('button.scatter_plot_link,cliffs_grid').get()[0] as HTMLButtonElement;
|
|
128
|
+
cliffsLink.click();
|
|
129
|
+
await DG.delay(100);
|
|
130
|
+
tv.grid.props.rowHeight = 180;
|
|
131
|
+
tv.grid.col('sequence') && (tv.grid.col('sequence')!.width = 300);
|
|
132
|
+
tv.grid.col('structure') && (tv.grid.col('structure')!.width = 300);
|
|
133
|
+
const cliffsGrid = Array.from(tv.viewers).find((v) => v !== tv.grid && v.type === DG.VIEWER.GRID) as DG.Grid;
|
|
134
|
+
if (cliffsGrid) {
|
|
135
|
+
cliffsGrid.props.rowHeight = 40;
|
|
136
|
+
cliffsGrid.col('seq_diff')!.width = 600;
|
|
137
|
+
tv.dockManager.dock(cliffsGrid, DG.DOCK_TYPE.DOWN, null, 'Cliffs', 0.35);
|
|
138
|
+
tv.dockManager.dock(activityCliffsViewer, DG.DOCK_TYPE.RIGHT, null, 'Activity Cliffs', 0.55);
|
|
139
|
+
}
|
|
140
|
+
} catch (err: any) {
|
|
141
|
+
handleError(err);
|
|
142
|
+
} finally {
|
|
143
|
+
ui.setUpdateIndicator(tv.root, false);
|
|
144
|
+
}
|
|
145
|
+
grok.shell.windows.help.showHelp('/help/datagrok/solutions/domains/bio/bio.md#activity-cliffs');
|
|
146
|
+
}
|
package/src/package.ts
CHANGED
|
@@ -49,7 +49,7 @@ import {MonomerLibManager} from './utils/monomer-lib/lib-manager';
|
|
|
49
49
|
import {getMonomerLibraryManagerLink, showManageLibrariesDialog, showManageLibrariesView} from './utils/monomer-lib/library-file-manager/ui';
|
|
50
50
|
import {demoBioSimDiv} from './demo/bio01-similarity-diversity';
|
|
51
51
|
import {demoSeqSpace} from './demo/bio01a-hierarchical-clustering-and-sequence-space';
|
|
52
|
-
import {
|
|
52
|
+
import {demoActivityCliffsCyclic} from './demo/bio01b-hierarchical-clustering-and-activity-cliffs';
|
|
53
53
|
import {demoToAtomicLevel} from './demo/bio03-atomic-level';
|
|
54
54
|
import {checkInputColumnUI} from './utils/check-input-column';
|
|
55
55
|
import {MsaWarning} from './utils/multiple-sequence-alignment';
|
|
@@ -71,6 +71,8 @@ import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
|
|
|
71
71
|
import {MonomerManager} from './utils/monomer-lib/monomer-manager/monomer-manager';
|
|
72
72
|
import {calculateScoresWithEmptyValues} from './utils/calculate-scores';
|
|
73
73
|
import {SeqHelper} from './utils/seq-helper/seq-helper';
|
|
74
|
+
import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
|
|
75
|
+
import {toAtomicLevelWidget} from './widgets/to-atomic-level-widget';
|
|
74
76
|
|
|
75
77
|
export const _package = new BioPackage(/*{debug: true}/**/);
|
|
76
78
|
|
|
@@ -639,6 +641,14 @@ export async function toAtomicLevelAction(seqCol: DG.Column) {
|
|
|
639
641
|
func.prepare({table: seqCol.dataFrame, seqCol: seqCol}).edit();
|
|
640
642
|
}
|
|
641
643
|
|
|
644
|
+
//name: Molecular Structure
|
|
645
|
+
//tags: panel, bio, widgets
|
|
646
|
+
//input: semantic_value sequence { semType: Macromolecule }
|
|
647
|
+
//output: widget result
|
|
648
|
+
export async function toAtomicLevelPanel(sequence: DG.SemanticValue): Promise<DG.Widget> {
|
|
649
|
+
return toAtomicLevelWidget(sequence);
|
|
650
|
+
}
|
|
651
|
+
|
|
642
652
|
//top-menu: Bio | Analyze | MSA...
|
|
643
653
|
//name: MSA
|
|
644
654
|
//description: Performs multiple sequence alignment
|
|
@@ -1115,10 +1125,9 @@ export async function demoBioSequenceSpace(): Promise<void> {
|
|
|
1115
1125
|
//meta.demoPath: Bioinformatics | Activity Cliffs
|
|
1116
1126
|
//description: Activity Cliffs analysis on Macromolecules data
|
|
1117
1127
|
//meta.path: /apps/Tutorials/Demo/Bioinformatics/Activity%20Cliffs
|
|
1118
|
-
//meta.isDemoScript: True
|
|
1119
1128
|
//meta.demoSkip: GROK-14320
|
|
1120
1129
|
export async function demoBioActivityCliffs(): Promise<void> {
|
|
1121
|
-
await
|
|
1130
|
+
await demoActivityCliffsCyclic();
|
|
1122
1131
|
}
|
|
1123
1132
|
|
|
1124
1133
|
// demoBio03
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as ui from 'datagrok-api/ui';
|
|
3
|
+
import * as DG from 'datagrok-api/dg';
|
|
4
|
+
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
5
|
+
import {_package, getSeqHelper, toAtomicLevel} from '../package';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export async function toAtomicLevelWidget(sequence: DG.SemanticValue): Promise<DG.Widget> {
|
|
9
|
+
const errorDiv = ui.divText('');
|
|
10
|
+
const errorWidget = DG.Widget.fromRoot(errorDiv);
|
|
11
|
+
try {
|
|
12
|
+
if (!sequence || !sequence.value) {
|
|
13
|
+
errorDiv.innerText = 'No sequence provided';
|
|
14
|
+
return errorWidget;
|
|
15
|
+
}
|
|
16
|
+
if (!sequence.cell || !sequence.cell.dart || !sequence.cell.dataFrame || !sequence.cell.column) {
|
|
17
|
+
errorDiv.innerText = 'Atomic level conversion requeires a sequence column';
|
|
18
|
+
return errorWidget;
|
|
19
|
+
}
|
|
20
|
+
const supportedUnits: string[] = [NOTATION.FASTA, NOTATION.SEPARATOR, NOTATION.HELM];
|
|
21
|
+
//todo: add support for custom notations
|
|
22
|
+
if (!supportedUnits.includes(sequence.cell.column.meta.units?.toLowerCase() ?? '')) {
|
|
23
|
+
errorDiv.innerText = 'Unsupported sequence notation. please use Bio | Polytool | Convert';
|
|
24
|
+
return errorWidget;
|
|
25
|
+
}
|
|
26
|
+
const seqHelper = await getSeqHelper();
|
|
27
|
+
const seqSh = seqHelper.getSeqHandler(sequence.cell.column);
|
|
28
|
+
if (!seqSh) {
|
|
29
|
+
errorDiv.innerText = 'No sequence handler found';
|
|
30
|
+
return errorWidget;
|
|
31
|
+
}
|
|
32
|
+
if ((seqSh.getSplitted(sequence.cell.rowIndex, 50)?.length ?? 100) > 40) {
|
|
33
|
+
errorDiv.innerText = 'Maximum number of monomers is 40';
|
|
34
|
+
return errorWidget;
|
|
35
|
+
}
|
|
36
|
+
const singleValCol = DG.Column.fromStrings('singleVal', [sequence.value]);
|
|
37
|
+
const sDf = DG.DataFrame.fromColumns([singleValCol]);
|
|
38
|
+
// copy over all the tags
|
|
39
|
+
Object.entries(sequence.cell.column.tags).forEach(([key, value]) => {
|
|
40
|
+
singleValCol.setTag(key, value as string);
|
|
41
|
+
});
|
|
42
|
+
await toAtomicLevel(sDf, singleValCol, sequence.cell.column.meta.units === NOTATION.HELM, false);
|
|
43
|
+
if (sDf.columns.length < 2) {
|
|
44
|
+
errorDiv.innerText = 'No structure generated';
|
|
45
|
+
return errorWidget;
|
|
46
|
+
}
|
|
47
|
+
const molCol = sDf.columns.byIndex(1);
|
|
48
|
+
const molfile = molCol.get(0);
|
|
49
|
+
if (!molfile) {
|
|
50
|
+
errorDiv.innerText = 'No structure generated';
|
|
51
|
+
return errorWidget;
|
|
52
|
+
}
|
|
53
|
+
molCol.semType = DG.SEMTYPE.MOLECULE;
|
|
54
|
+
const molSemanticValue = DG.SemanticValue.fromTableCell(sDf.cell(0, molCol.name));
|
|
55
|
+
const panel = ui.panels.infoPanel(molSemanticValue);
|
|
56
|
+
let molPanel: DG.Widget | null = null;
|
|
57
|
+
if (panel)
|
|
58
|
+
molPanel = DG.Widget.fromRoot(panel.root);
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
const root = grok.chem.drawMolecule(molfile, 300, 300, false);
|
|
62
|
+
root.style.cursor = 'pointer';
|
|
63
|
+
ui.tooltip.bind(root, 'Click to expand');
|
|
64
|
+
root.onclick = () => {
|
|
65
|
+
const width = window.innerWidth - 200;
|
|
66
|
+
const height = window.innerHeight - 200;
|
|
67
|
+
const bigMol = grok.chem.drawMolecule(molfile, width, height, false);
|
|
68
|
+
ui.dialog({title: 'Molecule'}).add(bigMol).showModal(true);
|
|
69
|
+
};
|
|
70
|
+
if (molPanel)
|
|
71
|
+
molPanel.root.prepend(root);
|
|
72
|
+
return molPanel ?? DG.Widget.fromRoot(root);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
_package.logger.error(e);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
errorDiv.innerText = 'No Structure generated';
|
|
78
|
+
return errorWidget;
|
|
79
|
+
}
|