@datagrok/sequence-translator 1.0.16 → 1.0.17
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/detectors.js +0 -28
- package/dist/package-test.js +3830 -3738
- package/dist/package.js +3826 -3734
- package/package.json +3 -1
- package/setup-unlink-clean.sh +21 -0
- package/src/autostart/calculations.ts +2 -2
- package/src/autostart/registration.ts +102 -37
- package/src/{axolabs/define-pattern.ts → axolabs-tab/axolabs-tab.ts} +2 -2
- package/src/axolabs-tab/define-pattern.ts +874 -0
- package/src/{axolabs → axolabs-tab}/draw-svg.ts +1 -1
- package/src/{axolabs → axolabs-tab}/helpers.ts +2 -2
- package/src/{autostart → hardcode-to-be-eliminated}/ICDs.ts +0 -0
- package/src/{autostart → hardcode-to-be-eliminated}/IDPs.ts +0 -0
- package/src/{structures-works → hardcode-to-be-eliminated}/const.ts +0 -0
- package/src/{axolabs → hardcode-to-be-eliminated}/constants.ts +0 -0
- package/src/{structures-works → hardcode-to-be-eliminated}/converters.ts +1 -1
- package/src/{structures-works → hardcode-to-be-eliminated}/map.ts +2 -2
- package/src/{autostart → hardcode-to-be-eliminated}/salts.ts +0 -0
- package/src/{autostart → hardcode-to-be-eliminated}/sources.ts +0 -0
- package/src/{autostart → hardcode-to-be-eliminated}/users.ts +0 -0
- package/src/{main/main-view.ts → main-tab/main-tab.ts} +27 -79
- package/src/package.ts +40 -23
- package/src/sdf-tab/sdf-tab.ts +163 -0
- package/src/{structures-works → sdf-tab}/sequence-codes-tools.ts +8 -5
- package/src/tests/smiles-tests.ts +2 -2
- package/src/utils/const.ts +0 -0
- package/src/{helpers.ts → utils/helpers.ts} +3 -3
- package/src/utils/sdf-add-columns.ts +3 -3
- package/src/utils/sdf-save-table.ts +4 -4
- package/src/utils/structures-works/draw-molecule.ts +84 -0
- package/src/{structures-works → utils/structures-works}/from-monomers.ts +15 -16
- package/src/{structures-works → utils/structures-works}/mol-transformations.ts +34 -52
- package/{test-SequenceTranslator-6288c2fbe346-cce4ac1d.html → test-SequenceTranslator-6288c2fbe346-695b7b55.html} +10 -10
- package/src/structures-works/save-sense-antisense.ts +0 -91
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {NUCLEOTIDES} from '../
|
|
1
|
+
import {NUCLEOTIDES} from '../hardcode-to-be-eliminated/map';
|
|
2
2
|
import {isOverhang, svg, textWidth, countOverhangsOnTheRightEdge, baseColor, textInsideCircle,
|
|
3
3
|
fontColorVisibleOnBackground, isOneDigitNumber} from './helpers';
|
|
4
4
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {AXOLABS_MAP} from '
|
|
2
|
-
import {NUCLEOTIDES} from '../
|
|
1
|
+
import {AXOLABS_MAP} from '../hardcode-to-be-eliminated/constants';
|
|
2
|
+
import {NUCLEOTIDES} from '../hardcode-to-be-eliminated/map';
|
|
3
3
|
|
|
4
4
|
export function isOverhang(modification: string): boolean {
|
|
5
5
|
return modification.slice(-3) == '(o)';
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {lcmsToGcrs, MODIFICATIONS} from './map';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
import {DELIMITER} from './map';
|
|
4
|
-
import {sortByStringLengthInDescendingOrder} from '../helpers';
|
|
4
|
+
import {sortByStringLengthInDescendingOrder} from '../utils/helpers';
|
|
5
5
|
//name: gcrsToLcms
|
|
6
6
|
//input: string nucleotides {semType: GCRS}
|
|
7
7
|
//output: string result {semType: LCMS}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
|
-
import {getAllCodesOfSynthesizer} from '
|
|
3
|
-
import {differenceOfTwoArrays} from '../helpers';
|
|
2
|
+
import {getAllCodesOfSynthesizer} from '../sdf-tab/sequence-codes-tools';
|
|
3
|
+
import {differenceOfTwoArrays} from '../utils/helpers';
|
|
4
4
|
|
|
5
5
|
export const DELIMITER = ';';
|
|
6
6
|
export const NUCLEOTIDES = ['A', 'G', 'C', 'U', 'T'];
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -3,24 +3,29 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import * as rxjs from 'rxjs';
|
|
6
|
-
import {convertSequence, undefinedInputSequence, isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
7
|
-
import {map} from '../structures-works/map';
|
|
8
|
-
import {MODIFICATIONS} from '../structures-works/const';
|
|
9
|
-
import {sequenceToSmiles, sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
10
6
|
import $ from 'cash-dom';
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
|
|
7
|
+
|
|
8
|
+
import {convertSequence, undefinedInputSequence, isValidSequence} from '../sdf-tab/sequence-codes-tools';
|
|
9
|
+
|
|
10
|
+
// todo: elminate completely
|
|
11
|
+
import {map} from '../hardcode-to-be-eliminated/map';
|
|
12
|
+
import {MODIFICATIONS} from '../hardcode-to-be-eliminated/const';
|
|
13
|
+
|
|
14
|
+
// todo: unify with lib bio monomers works
|
|
15
|
+
import {sequenceToSmiles, sequenceToMolV3000} from '../utils/structures-works/from-monomers';
|
|
16
|
+
import {drawMolecule} from '../utils/structures-works/draw-molecule';
|
|
17
|
+
|
|
18
|
+
import {download} from '../utils/helpers';
|
|
14
19
|
|
|
15
20
|
const defaultInput = 'fAmCmGmAmCpsmU'; // todo: capitalize constants
|
|
16
21
|
const sequenceWasCopied = 'Copied'; // todo: wrap hardcoded literals into constants
|
|
17
22
|
const tooltipSequence = 'Copy sequence';
|
|
18
23
|
|
|
19
|
-
export async function
|
|
24
|
+
export async function getMainTab(onSequenceChanged: (seq: string) => void): Promise<HTMLDivElement> {
|
|
20
25
|
const onInput: rxjs.Subject<string> = new rxjs.Subject<string>();
|
|
21
26
|
|
|
22
27
|
async function updateTableAndMolecule(sequence: string, inputFormat: string): Promise<void> {
|
|
23
|
-
|
|
28
|
+
moleculeImgDiv.innerHTML = '';
|
|
24
29
|
outputTableDiv.innerHTML = '';
|
|
25
30
|
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
26
31
|
|
|
@@ -56,77 +61,20 @@ export async function mainView(onSequenceChanged: (seq: string) => void): Promis
|
|
|
56
61
|
ui.div([
|
|
57
62
|
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
58
63
|
[item.key, item.value], ['Code', 'Sequence']).root,
|
|
59
|
-
])
|
|
64
|
+
])
|
|
60
65
|
);
|
|
61
66
|
|
|
62
|
-
if (outputSequenceObj.type
|
|
67
|
+
if (outputSequenceObj.type !== undefinedInputSequence && outputSequenceObj.Error !== undefinedInputSequence) {
|
|
63
68
|
const formCanvasWidth = 500;
|
|
64
69
|
const formCanvasHeight = 170;
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
74
|
-
output.synthesizer![0],
|
|
75
|
-
);
|
|
76
|
-
console.log(mol);
|
|
77
|
-
|
|
78
|
-
const addDiv = ui.div([], {style: {overflowX: 'scroll'}});
|
|
79
|
-
|
|
80
|
-
// addDiv size required, but now available before dialog show()
|
|
81
|
-
const coordinates = extractAtomDataV3000(mol);
|
|
82
|
-
const cw: number = $(window).width() * 0.80; // addDiv.clientWidth
|
|
83
|
-
const ch: number = $(window).height() * 0.70; // addDiv.clientHeight
|
|
84
|
-
const molWidth: number = Math.max(...coordinates.x) - Math.min(...coordinates.x);
|
|
85
|
-
const molHeight: number = Math.max(...coordinates.y) - Math.min(...coordinates.y);
|
|
86
|
-
|
|
87
|
-
const wR: number = cw / molWidth;
|
|
88
|
-
const hR: number = ch / molHeight;
|
|
89
|
-
const r: number = hR; // Math.max(wR, hR);
|
|
90
|
-
const dlgCanvasWidth = r * molWidth;
|
|
91
|
-
const dlgCanvasHeight = r * molHeight;
|
|
92
|
-
|
|
93
|
-
const dlgCanvas = ui.canvas(dlgCanvasWidth * window.devicePixelRatio, dlgCanvasHeight * window.devicePixelRatio);
|
|
94
|
-
dlgCanvas.style.width = `${dlgCanvasWidth}px`;
|
|
95
|
-
dlgCanvas.style.height = `${dlgCanvasHeight}px`;
|
|
96
|
-
|
|
97
|
-
// // @ts-ignore
|
|
98
|
-
// OCL.StructureView.drawMolecule(dlgCanvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
99
|
-
// await grok.chem.canvasMol(0, 0, dlgCanvas.width, dlgCanvas.height, dlgCanvas, mol, null,
|
|
100
|
-
// {setNewCoords: false, normalizeDepiction: false, straightenDepiction: false});
|
|
101
|
-
await grok.functions.call('Chem:canvasMol', {
|
|
102
|
-
x: 0, y: 0, w: dlgCanvas.width, h: dlgCanvas.height, canvas: dlgCanvas,
|
|
103
|
-
molString: mol, scaffoldMolString: '',
|
|
104
|
-
options: {normalizeDepiction: false, straightenDepiction: false}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
addDiv.appendChild(dlgCanvas);
|
|
108
|
-
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
109
|
-
.add(addDiv)
|
|
110
|
-
.showModal(true);
|
|
111
|
-
} catch (err) {
|
|
112
|
-
const errStr = errorToConsole(err);
|
|
113
|
-
console.error(errStr);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
$(formCanvas).on('mouseover', () => $(formCanvas).css('cursor', 'zoom-in'));
|
|
117
|
-
$(formCanvas).on('mouseout', () => $(formCanvas).css('cursor', 'default'));
|
|
118
|
-
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
119
|
-
output.synthesizer![0]);
|
|
120
|
-
// // @ts-ignore
|
|
121
|
-
// OCL.StructureView.drawMolecule(formCanvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
122
|
-
await grok.functions.call('Chem:canvasMol', {
|
|
123
|
-
x: 0, y: 0, w: formCanvas.width, h: formCanvas.height, canvas: formCanvas,
|
|
124
|
-
molString: mol, scaffoldMolString: '',
|
|
125
|
-
options: {normalizeDepiction: false, straightenDepiction: false}
|
|
126
|
-
});
|
|
127
|
-
moleculeSvgDiv.append(formCanvas);
|
|
128
|
-
} else
|
|
129
|
-
moleculeSvgDiv.innerHTML = '';
|
|
70
|
+
const molfile = sequenceToMolV3000(
|
|
71
|
+
inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
72
|
+
output.synthesizer![0]
|
|
73
|
+
);
|
|
74
|
+
await drawMolecule(moleculeImgDiv, formCanvasWidth, formCanvasHeight, molfile);
|
|
75
|
+
} else {
|
|
76
|
+
moleculeImgDiv.innerHTML = '';
|
|
77
|
+
}
|
|
130
78
|
} finally {
|
|
131
79
|
pi.close();
|
|
132
80
|
}
|
|
@@ -136,7 +84,7 @@ export async function mainView(onSequenceChanged: (seq: string) => void): Promis
|
|
|
136
84
|
inputFormatChoiceInput.onInput((format: string) => {
|
|
137
85
|
updateTableAndMolecule(inputSequenceField.value.replace(/\s/g, ''), format);
|
|
138
86
|
});
|
|
139
|
-
const
|
|
87
|
+
const moleculeImgDiv = ui.block([]);
|
|
140
88
|
const outputTableDiv = ui.div([]);
|
|
141
89
|
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => {
|
|
142
90
|
// Send event to DG.debounce()
|
|
@@ -228,7 +176,7 @@ export async function mainView(onSequenceChanged: (seq: string) => void): Promis
|
|
|
228
176
|
const topPanel = [
|
|
229
177
|
downloadMolFileIcon,
|
|
230
178
|
copySmilesIcon,
|
|
231
|
-
switchInput.root,
|
|
179
|
+
switchInput.root, // todo: remove from top panel
|
|
232
180
|
];
|
|
233
181
|
|
|
234
182
|
const v = grok.shell.v;
|
|
@@ -253,7 +201,7 @@ export async function mainView(onSequenceChanged: (seq: string) => void): Promis
|
|
|
253
201
|
ui.h1('Output'),
|
|
254
202
|
outputTableDiv,
|
|
255
203
|
]),
|
|
256
|
-
|
|
204
|
+
moleculeImgDiv,
|
|
257
205
|
], 'sequence'),
|
|
258
206
|
]),
|
|
259
207
|
codesTablesDiv,
|
package/src/package.ts
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
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
|
import {autostartOligoSdFileSubscription} from './autostart/registration';
|
|
5
|
-
import {defineAxolabsPattern} from './axolabs/define-pattern';
|
|
6
|
-
import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
|
|
7
|
-
import {mainView} from './main/main-view';
|
|
8
|
-
import {IMonomerLib, MonomerWorks, readLibrary} from '@datagrok-libraries/bio';
|
|
9
6
|
import {OligoSdFileApp} from './apps/oligo-sd-file-app';
|
|
10
7
|
|
|
8
|
+
// three tabs of the app's view
|
|
9
|
+
import {getMainTab} from './main-tab/main-tab';
|
|
10
|
+
import {getAxolabsTab} from './axolabs-tab/axolabs-tab';
|
|
11
|
+
import {getSdfTab} from './sdf-tab/sdf-tab';
|
|
12
|
+
|
|
13
|
+
const MAIN = 'MAIN';
|
|
14
|
+
const AXOLABS = 'AXOLABS';
|
|
15
|
+
const SDF = 'SDF';
|
|
16
|
+
|
|
17
|
+
const SEQUENCE_TRANSLATOR = 'Sequence Translator';
|
|
18
|
+
const DEFAULT_SEQUENCE = 'fAmCmGmAmCpsmU';
|
|
19
|
+
const DEFAULT_LIB_FILENAME = 'helmLib.json';
|
|
20
|
+
|
|
21
|
+
import {IMonomerLib, MonomerWorks, readLibrary} from '@datagrok-libraries/bio';
|
|
22
|
+
|
|
11
23
|
export const _package = new DG.Package();
|
|
12
24
|
|
|
13
25
|
const LIB_PATH = 'System:AppData/SequenceTranslator';
|
|
@@ -26,9 +38,9 @@ export function getMonomerLib() {
|
|
|
26
38
|
//name: Sequence Translator
|
|
27
39
|
//tags: app
|
|
28
40
|
export async function sequenceTranslator(): Promise<void> {
|
|
29
|
-
monomerLib = await readLibrary(LIB_PATH,
|
|
41
|
+
monomerLib = await readLibrary(LIB_PATH, DEFAULT_LIB_FILENAME);
|
|
30
42
|
|
|
31
|
-
if (monomerWorks
|
|
43
|
+
if (monomerWorks === null)
|
|
32
44
|
monomerWorks = new MonomerWorks(monomerLib);
|
|
33
45
|
|
|
34
46
|
const windows = grok.shell.windows;
|
|
@@ -36,22 +48,25 @@ export async function sequenceTranslator(): Promise<void> {
|
|
|
36
48
|
windows.showToolbox = false;
|
|
37
49
|
windows.showHelp = false;
|
|
38
50
|
|
|
39
|
-
let urlParams
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
let urlParams = new URLSearchParams(window.location.search);
|
|
52
|
+
|
|
53
|
+
let mainSeq: string = DEFAULT_SEQUENCE;
|
|
54
|
+
const view = grok.shell.newView(SEQUENCE_TRANSLATOR, []);
|
|
55
|
+
view.box = true;
|
|
56
|
+
|
|
57
|
+
const tabControl = ui.tabControl({
|
|
58
|
+
[MAIN]: await getMainTab((seq) => {
|
|
45
59
|
mainSeq = seq;
|
|
46
60
|
urlParams = new URLSearchParams();
|
|
47
61
|
urlParams.set('seq', mainSeq);
|
|
48
62
|
updatePath();
|
|
49
63
|
}),
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
[AXOLABS]: getAxolabsTab(),
|
|
65
|
+
[SDF]: getSdfTab(),
|
|
52
66
|
});
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
|
|
68
|
+
tabControl.onTabChanged.subscribe(() => {
|
|
69
|
+
if (tabControl.currentPane.name !== MAIN)
|
|
55
70
|
urlParams.delete('seq');
|
|
56
71
|
else
|
|
57
72
|
urlParams.set('seq', mainSeq);
|
|
@@ -61,26 +76,28 @@ export async function sequenceTranslator(): Promise<void> {
|
|
|
61
76
|
function updatePath() {
|
|
62
77
|
const urlParamsTxt: string = Object.entries(urlParams)
|
|
63
78
|
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join('&');
|
|
64
|
-
|
|
79
|
+
view.path = '/apps/SequenceTranslator/SequenceTranslator' + `/${tabControl.currentPane.name}/?${urlParamsTxt}`;
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
const pathParts: string[] = window.location.pathname.split('/');
|
|
68
83
|
if (pathParts.length >= 5) {
|
|
69
84
|
const tabName: string = pathParts[5];
|
|
70
|
-
|
|
85
|
+
tabControl.currentPane = tabControl.getPane(tabName);
|
|
71
86
|
}
|
|
72
87
|
|
|
73
|
-
|
|
74
|
-
console.debug('SequenceTranslator: app sequenceTranslator() ' + `
|
|
88
|
+
view.append(tabControl);
|
|
89
|
+
// console.debug('SequenceTranslator: app sequenceTranslator() ' + `view.path='${view.path}', view.basePath='${view.basePath}'.`);
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
//tags: autostart
|
|
78
|
-
|
|
93
|
+
export async function autostartST() {
|
|
94
|
+
autostartOligoSdFileSubscription();
|
|
95
|
+
};
|
|
79
96
|
|
|
80
97
|
//name: oligoSdFileApp
|
|
81
98
|
//description: Test/demo app for oligoSdFile
|
|
82
99
|
export async function oligoSdFileApp() {
|
|
83
|
-
console.debug('SequenceTranslator: package.ts oligoSdFileApp()');
|
|
100
|
+
// console.debug('SequenceTranslator: package.ts oligoSdFileApp()');
|
|
84
101
|
|
|
85
102
|
const pi = DG.TaskBarProgressIndicator.create('open oligoSdFile app');
|
|
86
103
|
try {
|
|
@@ -92,4 +109,4 @@ export async function oligoSdFileApp() {
|
|
|
92
109
|
} finally {
|
|
93
110
|
pi.close();
|
|
94
111
|
}
|
|
95
|
-
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
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 * as rxjs from 'rxjs';
|
|
5
|
+
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
6
|
+
|
|
7
|
+
import $ from 'cash-dom';
|
|
8
|
+
|
|
9
|
+
import {download} from '../utils/helpers';
|
|
10
|
+
|
|
11
|
+
import {sequenceToMolV3000} from '../utils/structures-works/from-monomers';
|
|
12
|
+
import {linkStrandsV3000} from '../utils/structures-works/mol-transformations';
|
|
13
|
+
import {getFormat} from './sequence-codes-tools';
|
|
14
|
+
|
|
15
|
+
import {drawMolecule} from '../utils/structures-works/draw-molecule';
|
|
16
|
+
|
|
17
|
+
function getMolfileForImg(
|
|
18
|
+
ss: string, as: string,
|
|
19
|
+
as2: string | null = null,
|
|
20
|
+
invertSS: boolean, invertAS: boolean, invertAS2: boolean,
|
|
21
|
+
useChiral: boolean
|
|
22
|
+
): string {
|
|
23
|
+
const formatAs = getFormat(as);
|
|
24
|
+
const formatSs = getFormat(ss);
|
|
25
|
+
let formatAs2: string | null = null;
|
|
26
|
+
let molAS2: string | null = null;
|
|
27
|
+
|
|
28
|
+
let molSS = '';
|
|
29
|
+
let molAS = '';
|
|
30
|
+
try {
|
|
31
|
+
// a workaround to get the SS depicted in case AS is empty
|
|
32
|
+
molSS = sequenceToMolV3000(ss, invertSS, false, formatSs!);
|
|
33
|
+
molAS = sequenceToMolV3000(as, invertAS, false, formatAs!);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
const errStr = errorToConsole(err);
|
|
36
|
+
console.error(errStr);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (as2 !== null && as2 !== '') {
|
|
40
|
+
formatAs2 = getFormat(as2!);
|
|
41
|
+
molAS2 = sequenceToMolV3000(as2, invertAS2!, false, formatAs2!);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const antiStrands = molAS2 === null ? [molAS] : [molAS, molAS2];
|
|
45
|
+
const resultingMolfile = linkStrandsV3000({senseStrands: [molSS], antiStrands: antiStrands}, useChiral);
|
|
46
|
+
return resultingMolfile;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function saveSdf(as: string, ss: string,
|
|
50
|
+
oneEntity: boolean, useChiral: boolean,
|
|
51
|
+
invertSS: boolean, invertAS: boolean,
|
|
52
|
+
as2: string | null = null, invertAS2: boolean | null
|
|
53
|
+
): void {
|
|
54
|
+
const formatAs = getFormat(as);
|
|
55
|
+
const formatSs = getFormat(ss);
|
|
56
|
+
let formatAs2: string | null = null;
|
|
57
|
+
let molAS2: string | null = null;
|
|
58
|
+
|
|
59
|
+
const molSS = sequenceToMolV3000(ss, invertSS, false, formatSs!);
|
|
60
|
+
const molAS = sequenceToMolV3000(as, invertAS, false, formatAs!);
|
|
61
|
+
|
|
62
|
+
if (as2 !== null && as2 !== '') {
|
|
63
|
+
formatAs2 = getFormat(as2!);
|
|
64
|
+
molAS2 = sequenceToMolV3000(as2, invertAS2!, false, formatAs2!);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let result: string;
|
|
68
|
+
if (oneEntity) {
|
|
69
|
+
const antiStrands = molAS2 === null ? [molAS] : [molAS, molAS2];
|
|
70
|
+
result = linkStrandsV3000({senseStrands: [molSS], antiStrands: antiStrands}, useChiral) + '\n$$$$\n';
|
|
71
|
+
} else {
|
|
72
|
+
result =
|
|
73
|
+
molSS + '\n' +
|
|
74
|
+
`> <Sequence>\nSense Strand\n$$$$\n` +
|
|
75
|
+
molAS + '\n' +
|
|
76
|
+
`> <Sequence>\nAnti Sense\n$$$$\n`;
|
|
77
|
+
|
|
78
|
+
if (molAS2) {
|
|
79
|
+
result += molAS2+ '\n' +
|
|
80
|
+
`> <Sequence>\nAnti Sense 2\n$$$$\n`;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// construct date-time in the form yyyy-mm-dd_hh-mm-ss
|
|
85
|
+
const date = new Date();
|
|
86
|
+
function pad(x: number): string {
|
|
87
|
+
return (x >= 10) ? x.toString() : '0' + x.toString();
|
|
88
|
+
}
|
|
89
|
+
const dateString: string = date.getFullYear() + '-' + pad(date.getMonth() + 1) +
|
|
90
|
+
'-' + pad(date.getDate()) + '_' + pad(date.getHours()) + '-' +
|
|
91
|
+
pad(date.getMinutes()) + '-' + pad(date.getSeconds());
|
|
92
|
+
|
|
93
|
+
download(`SequenceTranslator-${dateString}.sdf`, encodeURIComponent(result));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** UI of the SDF tab on the application's view */
|
|
97
|
+
export function getSdfTab(): HTMLDivElement {
|
|
98
|
+
const onInput: rxjs.Subject<string> = new rxjs.Subject<string>();
|
|
99
|
+
|
|
100
|
+
// inputs
|
|
101
|
+
const inputColHeader = ui.h1('Sequences');
|
|
102
|
+
const ssInput = ui.textInput('Sense Strand', '', () => { onInput.next(); });
|
|
103
|
+
ssInput.root.style.color = 'red';
|
|
104
|
+
const asInput = ui.textInput('Anti Sense', '', () => { onInput.next(); });
|
|
105
|
+
const as2Input = ui.textInput('Anti Sense 2', '', () => { onInput.next(); });
|
|
106
|
+
const saveEntity = ui.boolInput('Save as one entity', true);
|
|
107
|
+
const useChiralInput = ui.boolInput('Use chiral', true);
|
|
108
|
+
|
|
109
|
+
// default values
|
|
110
|
+
const straight = '5 prime -> 3 prime';
|
|
111
|
+
const inverse = '3 prime -> 5 prime';
|
|
112
|
+
let invertSS = false;
|
|
113
|
+
let invertAS = false;
|
|
114
|
+
const invertAS2 = false;
|
|
115
|
+
|
|
116
|
+
// choice inputs
|
|
117
|
+
const ssDirection = ui.choiceInput('SS direction', straight, [straight, inverse]);
|
|
118
|
+
ssDirection.onChanged(() => { invertSS = ssDirection.value === inverse; });
|
|
119
|
+
const asDirection = ui.choiceInput('AS direction', straight, [straight, inverse]);
|
|
120
|
+
asDirection.onChanged(() => { invertAS = asDirection.value === inverse; });
|
|
121
|
+
const as2Direction = ui.choiceInput('AS 2 direction', straight, [straight, inverse]);
|
|
122
|
+
as2Direction.onChanged(() => { invertAS = asDirection.value === inverse; });
|
|
123
|
+
|
|
124
|
+
// molecule image
|
|
125
|
+
const moleculeImgDiv = ui.block([]);
|
|
126
|
+
DG.debounce<string>(onInput, 300).subscribe(async () => {
|
|
127
|
+
let molfile = '';
|
|
128
|
+
try {
|
|
129
|
+
molfile = getMolfileForImg(
|
|
130
|
+
ssInput.value, asInput.value, as2Input.value, invertSS, invertAS, invertAS2, useChiralInput.value!
|
|
131
|
+
);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
const errStr = errorToConsole(err);
|
|
134
|
+
console.error(errStr);
|
|
135
|
+
}
|
|
136
|
+
// todo: calculate relative numbers
|
|
137
|
+
const canvasWidth = 500;
|
|
138
|
+
const canvasHeight = 170;
|
|
139
|
+
// todo: remove div with image if molfile empty
|
|
140
|
+
await drawMolecule(moleculeImgDiv, canvasWidth, canvasHeight, molfile);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const saveButton = ui.buttonsInput([
|
|
144
|
+
ui.bigButton('Save SDF', () =>
|
|
145
|
+
saveSdf(
|
|
146
|
+
asInput.value, ssInput.value, saveEntity.value!,
|
|
147
|
+
useChiralInput.value!, invertSS, invertAS, as2Input.value, invertAS2)
|
|
148
|
+
)
|
|
149
|
+
]);
|
|
150
|
+
//@ts-ignore
|
|
151
|
+
// the above line is recommended by Dmitry because saveButton has wrong return
|
|
152
|
+
// type
|
|
153
|
+
const form1 = ui.form([inputColHeader, ssInput, asInput, as2Input, saveButton]);
|
|
154
|
+
form1.className = 'ui-form ui-form-wide';
|
|
155
|
+
const form2 = ui.form([ssDirection, asDirection, as2Direction, saveEntity, useChiralInput]);
|
|
156
|
+
form2.className = 'ui-form ui-form-wide';
|
|
157
|
+
|
|
158
|
+
const body = ui.divV([ui.divH([ui.block([form1]), form2]), moleculeImgDiv]);
|
|
159
|
+
$(form1).find('textarea').css('flex-grow', '1');
|
|
160
|
+
$(form1).find('label').css('max-width', '140px');
|
|
161
|
+
|
|
162
|
+
return body;
|
|
163
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, DELIMITER, gcrsCodesWithoutSmiles, NUCLEOTIDES
|
|
3
|
+
} from '../hardcode-to-be-eliminated/map';
|
|
4
|
+
import {sortByStringLengthInDescendingOrder} from '../utils/helpers';
|
|
5
|
+
import {
|
|
6
|
+
asoGapmersNucleotidesToBioSpring, asoGapmersNucleotidesToGcrs,
|
|
5
7
|
asoGapmersBioSpringToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12, siRnaNucleotideToBioSpringSenseStrand,
|
|
6
8
|
siRnaNucleotideToAxolabsSenseStrand, siRnaNucleotidesToGcrs, siRnaBioSpringToNucleotides,
|
|
7
9
|
siRnaBioSpringToAxolabs, siRnaBioSpringToGcrs, siRnaAxolabsToNucleotides,
|
|
8
10
|
siRnaAxolabsToBioSpring, siRnaAxolabsToGcrs, siRnaGcrsToNucleotides,
|
|
9
|
-
siRnaGcrsToBioSpring, siRnaGcrsToAxolabs, gcrsToNucleotides, gcrsToLcms
|
|
11
|
+
siRnaGcrsToBioSpring, siRnaGcrsToAxolabs, gcrsToNucleotides, gcrsToLcms
|
|
12
|
+
} from '../hardcode-to-be-eliminated/converters';
|
|
10
13
|
|
|
11
14
|
const noTranslationTableAvailable = 'No translation table available';
|
|
12
15
|
export const undefinedInputSequence = 'Type of input sequence is undefined';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {category, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
2
|
-
import {sequenceToSmiles} from '../structures-works/from-monomers';
|
|
3
|
-
import {SYNTHESIZERS} from '../
|
|
2
|
+
import {sequenceToSmiles} from '../utils/structures-works/from-monomers';
|
|
3
|
+
import {SYNTHESIZERS} from '../hardcode-to-be-eliminated/map';
|
|
4
4
|
|
|
5
5
|
category('sequence-translator', () => {
|
|
6
6
|
// test('AGGTCCTCTTGACTTAGGCC', async () => {
|
|
File without changes
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
|
|
3
3
|
export function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
4
|
-
return array.sort(function(a, b) {return b.length - a.length;});
|
|
4
|
+
return array.sort(function(a, b) { return b.length - a.length; });
|
|
5
5
|
}
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
export function stringify(items: string[]): string {
|
|
8
8
|
return '["' + items.join('", "') + '"]';
|
|
9
9
|
}
|
|
@@ -17,7 +17,7 @@ export function download(name: string, href: string): void {
|
|
|
17
17
|
|
|
18
18
|
export function removeEmptyRows(t: DG.DataFrame, colToCheck: DG.Column): DG.DataFrame {
|
|
19
19
|
for (let i = t.rowCount - 1; i > -1; i--) {
|
|
20
|
-
if (colToCheck.getString(i)
|
|
20
|
+
if (colToCheck.getString(i) === '')
|
|
21
21
|
t.rows.removeAt(i, 1, false);
|
|
22
22
|
}
|
|
23
23
|
return t;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import {COL_NAMES, GENERATED_COL_NAMES, SEQUENCE_TYPES} from '../autostart/constants';
|
|
3
3
|
import * as grok from 'datagrok-api/grok';
|
|
4
|
-
import {removeEmptyRows} from '../helpers';
|
|
4
|
+
import {removeEmptyRows} from '../utils/helpers';
|
|
5
5
|
import {parseStrandsFromDuplexCell, parseStrandsFromTriplexOrDimerCell} from './parse';
|
|
6
|
-
import {isValidSequence} from '../
|
|
6
|
+
import {isValidSequence} from '../sdf-tab/sequence-codes-tools';
|
|
7
7
|
import {batchMolWeight, molecularWeight, saltMass, saltMolWeigth} from '../autostart/calculations';
|
|
8
|
-
import {weightsObj} from '../
|
|
8
|
+
import {weightsObj} from '../hardcode-to-be-eliminated/map';
|
|
9
9
|
|
|
10
10
|
export class SdfColumnsExistsError extends Error {
|
|
11
11
|
constructor(message: string) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import {COL_NAMES, GENERATED_COL_NAMES, SEQUENCE_TYPES} from '../autostart/constants';
|
|
3
|
-
import {differenceOfTwoArrays, download} from '../helpers';
|
|
3
|
+
import {differenceOfTwoArrays, download} from '../utils/helpers';
|
|
4
4
|
import * as grok from 'datagrok-api/grok';
|
|
5
|
-
import {SYNTHESIZERS} from '../
|
|
6
|
-
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
5
|
+
import {SYNTHESIZERS} from '../hardcode-to-be-eliminated/map';
|
|
6
|
+
import {sequenceToMolV3000} from '../utils/structures-works/from-monomers';
|
|
7
7
|
import {parseStrandsFromDuplexCell, parseStrandsFromTriplexOrDimerCell} from './parse';
|
|
8
|
-
import {linkStrandsV3000} from '../structures-works/mol-transformations';
|
|
8
|
+
import {linkStrandsV3000} from '../utils/structures-works/mol-transformations';
|
|
9
9
|
|
|
10
10
|
export async function sdfSaveTable(table: DG.DataFrame, onError: (rowI: number, err: any) => void) {
|
|
11
11
|
if (GENERATED_COL_NAMES.some((colName) => !table.columns.contains(colName))) {
|