@datagrok/sequence-translator 1.8.0 → 1.9.1
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 +4 -0
- 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/package.json +3 -3
- package/src/apps/translator/view/ui.ts +1 -1
- package/src/package-test.ts +1 -1
- package/src/package.ts +7 -0
- package/src/polytool/pt-combine-dialog.ts +131 -0
- package/test-console-output-1.log +82 -104
- package/test-record-1.mp4 +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.9.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Leonid Stolbov",
|
|
7
7
|
"email": "lstolbov@datagrok.ai"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@datagrok-libraries/utils": "^4.3.7",
|
|
29
29
|
"@types/react": "^18.0.15",
|
|
30
30
|
"cash-dom": "^8.1.0",
|
|
31
|
-
"datagrok-api": "^1.
|
|
31
|
+
"datagrok-api": "^1.23.0",
|
|
32
32
|
"lodash": "^4.17.21",
|
|
33
33
|
"object-hash": "^3.0.0",
|
|
34
34
|
"openchemlib": "6.0.1",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"build-all": "npm --prefix ./../../libraries/chem-meta run build && npm --prefix ./../../js-api run build && npm --prefix ./../../libraries/utils run build && npm --prefix ./../../libraries/bio run build && npm --prefix ./../../libraries/tutorials run build && npm run build"
|
|
84
84
|
},
|
|
85
85
|
"canEdit": [
|
|
86
|
-
"
|
|
86
|
+
"Administrators"
|
|
87
87
|
],
|
|
88
88
|
"canView": [
|
|
89
89
|
"All users"
|
|
@@ -471,7 +471,7 @@ class ColumnInputsManager {
|
|
|
471
471
|
private selectColumnIfTableNotNull(
|
|
472
472
|
table: DG.DataFrame | null, columnName: string, columnLabel: REQUIRED_COLUMN_LABEL
|
|
473
473
|
): void {
|
|
474
|
-
if (table !== null) {
|
|
474
|
+
if (table !== null && columnName) {
|
|
475
475
|
const selectedColumn = table.getCol(columnName);
|
|
476
476
|
this.eventBus.selectColumn(columnLabel, selectedColumn);
|
|
477
477
|
}
|
package/src/package-test.ts
CHANGED
|
@@ -34,5 +34,5 @@ export async function test(category: string, test: string, testContext: TestCont
|
|
|
34
34
|
|
|
35
35
|
//name: initAutoTests
|
|
36
36
|
export async function initAutoTests() {
|
|
37
|
-
await initTests(_package, _package.getModule('package-test.js'));
|
|
37
|
+
await initTests(_package as any, _package.getModule('package-test.js'));
|
|
38
38
|
}
|
package/src/package.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {CyclizedNotationProvider} from './utils/cyclized';
|
|
|
27
27
|
import {getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
28
28
|
import {PolyToolTags} from './consts';
|
|
29
29
|
import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
30
|
+
import { getPTCombineDialog } from './polytool/pt-combine-dialog';
|
|
30
31
|
|
|
31
32
|
export const _package: OligoToolkitPackage = new OligoToolkitPackage({debug: true}/**/);
|
|
32
33
|
|
|
@@ -302,6 +303,12 @@ export async function getPtChemEnumeratorDialog(cell?: DG.Cell) {
|
|
|
302
303
|
return polyToolEnumerateChemUI(cell);
|
|
303
304
|
}
|
|
304
305
|
|
|
306
|
+
//name: Combine Sequences
|
|
307
|
+
//top-menu: Bio | PolyTool | Combine Sequences...
|
|
308
|
+
export async function getPolyToolCombineDialog() {
|
|
309
|
+
getPTCombineDialog();
|
|
310
|
+
}
|
|
311
|
+
|
|
305
312
|
|
|
306
313
|
//name: applyNotationProviderForHarmonizedSequence
|
|
307
314
|
//input: column col
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
|
|
5
|
+
export async function getPTCombineDialog() {
|
|
6
|
+
|
|
7
|
+
const createEditor = () => {
|
|
8
|
+
const editorDiv = ui.divH([]);
|
|
9
|
+
const tableEditor = ui.input.table('Table', {value: undefined, tooltipText: 'Table with sequences'});
|
|
10
|
+
const columnEditor = ui.input.choice('Column', {items: [] as string[], value: undefined, tooltipText: 'Sequence column'});
|
|
11
|
+
|
|
12
|
+
tableEditor.onChanged.subscribe(async () => {
|
|
13
|
+
const table = tableEditor.value;
|
|
14
|
+
if (!table) {
|
|
15
|
+
columnEditor.items = [];
|
|
16
|
+
columnEditor.value = null;
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
await table.meta.detectSemanticTypes();
|
|
20
|
+
await grok.data.detectSemanticTypes(table);
|
|
21
|
+
const stringColumns = Array.from(table.columns.categorical);
|
|
22
|
+
const stringColumnsNames = stringColumns.map((c) => c.name);
|
|
23
|
+
columnEditor.items = stringColumnsNames;
|
|
24
|
+
columnEditor.value = stringColumns.find((c) => c.semType === DG.SEMTYPE.MACROMOLECULE)?.name ?? stringColumnsNames.find((c) => {
|
|
25
|
+
const lc = c.toLowerCase();
|
|
26
|
+
return lc.includes('seq') || lc.includes('pep');
|
|
27
|
+
}) ?? stringColumnsNames[0];
|
|
28
|
+
});
|
|
29
|
+
editorDiv.appendChild(tableEditor.root);
|
|
30
|
+
editorDiv.appendChild(columnEditor.root);
|
|
31
|
+
editorDiv.style.alignItems = 'center';
|
|
32
|
+
return {root: editorDiv, getValue: () => ({table: tableEditor.value, column: columnEditor.value})};
|
|
33
|
+
}
|
|
34
|
+
type Editor = ReturnType<typeof createEditor>;
|
|
35
|
+
|
|
36
|
+
const editors: Editor[] = [];
|
|
37
|
+
const editorsDiv = ui.divV([]);
|
|
38
|
+
|
|
39
|
+
const insertNewEditor = (index: number) => {
|
|
40
|
+
const editorDiv = createEditor();
|
|
41
|
+
const removeButton = ui.icons.delete(() => {
|
|
42
|
+
if (!editorDiv.root.parentElement || editors.length < 2)
|
|
43
|
+
return;
|
|
44
|
+
editorDiv.root.remove();
|
|
45
|
+
const editorIndex = editors.indexOf(editorDiv);
|
|
46
|
+
if (editorIndex !== -1) {
|
|
47
|
+
editors.splice(editorIndex, 1);
|
|
48
|
+
}
|
|
49
|
+
}, 'Remove');
|
|
50
|
+
const addEditor = ui.icons.add(() => {
|
|
51
|
+
let editorIndex = editors.indexOf(editorDiv);
|
|
52
|
+
if (editorIndex === -1) {
|
|
53
|
+
editorIndex = editors.length;
|
|
54
|
+
}
|
|
55
|
+
insertNewEditor(editorIndex + 1);
|
|
56
|
+
}, 'Add');
|
|
57
|
+
editorDiv.root.appendChild(removeButton);
|
|
58
|
+
editorDiv.root.appendChild(addEditor);
|
|
59
|
+
removeButton.style.marginLeft = '8px';
|
|
60
|
+
removeButton.style.marginRight = '8px';
|
|
61
|
+
removeButton.style.color = 'var(--blue-1)';
|
|
62
|
+
addEditor.style.color = 'var(--blue-1)';
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
const prevEditor = editors[index];
|
|
66
|
+
if (prevEditor) {
|
|
67
|
+
editorsDiv.insertBefore(editorDiv.root, prevEditor.root);
|
|
68
|
+
} else {
|
|
69
|
+
editorsDiv.appendChild(editorDiv.root);
|
|
70
|
+
}
|
|
71
|
+
editors.splice(index, 0, editorDiv);
|
|
72
|
+
}
|
|
73
|
+
insertNewEditor(0);
|
|
74
|
+
|
|
75
|
+
function validate() {
|
|
76
|
+
const values = editors.map((e) => e.getValue());
|
|
77
|
+
const tables = values.map((v) => v.table);
|
|
78
|
+
const columns = values.map((v) => v.column);
|
|
79
|
+
return tables.every((t) => !!t) && columns.every((c) => !!c);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const separatorInput = ui.input.string('Separator', {value: '-', tooltipText: 'Separator for sequences', nullable: false});
|
|
83
|
+
|
|
84
|
+
ui.dialog('Combine Sequences')
|
|
85
|
+
.add(editorsDiv)
|
|
86
|
+
.add(separatorInput.root)
|
|
87
|
+
.onOK(async () => {
|
|
88
|
+
if (!validate()) {
|
|
89
|
+
grok.shell.error('Please fill all the fields');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const values = editors.map((e) => e.getValue());
|
|
93
|
+
const tables = values.map((v) => v.table);
|
|
94
|
+
const columns = values.map((v) => v.column);
|
|
95
|
+
const separator = separatorInput.value;
|
|
96
|
+
const cols = columns.map((c, i) => tables[i]!.col(c!)!.toList().filter((v) => !!v));
|
|
97
|
+
// do a DFS to generate all combinations
|
|
98
|
+
let curIndex = 0;
|
|
99
|
+
const totalLength = cols.reduce((acc, c) => acc * c.length, 1);
|
|
100
|
+
if (totalLength > 10_000_000) {
|
|
101
|
+
grok.shell.error('Too many combinations. Maximum allowed is 10M');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const result: string[] = new Array(totalLength).fill(null);
|
|
105
|
+
|
|
106
|
+
const dfs = (cur: string, depth: number) => {
|
|
107
|
+
if (depth === cols.length) {
|
|
108
|
+
result[curIndex++] = cur;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const actCur = `${cur}${cur ? separator : ''}`;
|
|
112
|
+
const col = cols[depth];
|
|
113
|
+
for (let i = 0; i < cols[depth].length; i++) {
|
|
114
|
+
dfs(actCur + col[i], depth + 1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
dfs('', 0);
|
|
118
|
+
const df = DG.DataFrame.fromColumns([DG.Column.fromStrings('Combined', result)]);
|
|
119
|
+
df.name = 'Combined Sequences';
|
|
120
|
+
await df.meta.detectSemanticTypes();
|
|
121
|
+
await grok.data.detectSemanticTypes(df);
|
|
122
|
+
grok.shell.addTableView(df);
|
|
123
|
+
})
|
|
124
|
+
.show({resizable: true});
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
}
|