@datagrok/bio 2.0.13 → 2.0.16
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/dist/package-test.js +1862 -1169
- package/dist/package.js +4025 -3457
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +135 -152
- package/files/data/sample_HELM_empty_vals.csv +537 -537
- package/files/samples/sample_HELM.csv +540 -540
- package/package.json +19 -12
- package/scripts/read-tree-pkl.py +215 -0
- package/src/__jest__/remote.test.ts +6 -4
- package/src/__jest__/test-node.ts +1 -1
- package/src/{utils → analysis}/sequence-activity-cliffs.ts +33 -30
- package/src/analysis/sequence-diversity-viewer.ts +48 -0
- package/src/analysis/sequence-search-base-viewer.ts +81 -0
- package/src/analysis/sequence-similarity-viewer.ts +107 -0
- package/src/{utils → analysis}/sequence-space.ts +0 -0
- package/src/calculations/monomerLevelMols.ts +64 -20
- package/src/package-test.ts +2 -1
- package/src/package.ts +57 -3
- package/src/substructure-search/substructure-search.ts +65 -0
- package/src/tests/WebLogo-test.ts +6 -6
- package/src/tests/activity-cliffs-tests.ts +8 -16
- package/src/tests/activity-cliffs-utils.ts +3 -2
- package/src/tests/sequence-space-test.ts +7 -14
- package/src/tests/similarity-diversity-tests.ts +78 -0
- package/src/utils/cell-renderer.ts +81 -68
- package/src/utils/ui-utils.ts +4 -0
- package/src/viewers/vd-regions-viewer.ts +2 -1
- package/src/widgets/representations.ts +58 -0
- package/test-Bio-7770371320b2-f8f97c6e.html +0 -374
|
@@ -11,7 +11,6 @@ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
|
11
11
|
|
|
12
12
|
const undefinedColor = 'rgb(100,100,100)';
|
|
13
13
|
const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string = WebLogo.monomerToShort;
|
|
14
|
-
const gapRenderer = 5;
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
function getPaletteByType(paletteType: string): SeqPalette {
|
|
@@ -61,10 +60,15 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
61
60
|
|
|
62
61
|
get defaultWidth(): number { return 230; }
|
|
63
62
|
|
|
63
|
+
onClick(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
64
|
+
gridCell.cell.column.temp['current-word'] = gridCell.cell.value;
|
|
65
|
+
gridCell.grid.invalidate();
|
|
66
|
+
}
|
|
67
|
+
|
|
64
68
|
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
65
|
-
if (gridCell.cell.column.getTag(UnitsHandler.TAGS.aligned) !== 'SEQ.MSA')
|
|
69
|
+
if (gridCell.cell.column.getTag(UnitsHandler.TAGS.aligned) !== 'SEQ.MSA')
|
|
66
70
|
return;
|
|
67
|
-
|
|
71
|
+
|
|
68
72
|
const maxLengthWordsSum = gridCell.cell.column.temp['bio-sum-maxLengthWords'];
|
|
69
73
|
const maxIndex = gridCell.cell.column.temp['bio-maxIndex'];
|
|
70
74
|
const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x);
|
|
@@ -84,16 +88,16 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
84
88
|
} else if (argsX > maxLengthWordsSum[mid + 1]) {
|
|
85
89
|
left = mid + 1;
|
|
86
90
|
}
|
|
87
|
-
if (left == right)
|
|
91
|
+
if (left == right)
|
|
88
92
|
found = true;
|
|
89
|
-
}
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
|
|
93
96
|
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
94
97
|
const splitterFunc: SplitterFunc = WebLogo.getSplitter('separator', separator);
|
|
95
98
|
const subParts: string[] = splitterFunc(gridCell.cell.value);
|
|
96
|
-
(((subParts[left]?.length ?? 0) > 0)) ?
|
|
99
|
+
(((subParts[left]?.length ?? 0) > 0)) ?
|
|
100
|
+
ui.tooltip.show(ui.div(subParts[left]), e.x + 16, e.y + 16) : ui.tooltip.hide();
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
/**
|
|
@@ -131,45 +135,52 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
131
135
|
|
|
132
136
|
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
133
137
|
const splitLimit = gridCell.bounds.width / 5;
|
|
134
|
-
const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, separator,
|
|
138
|
+
const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, separator, splitLimit);
|
|
139
|
+
const referenceSequence: string[] = splitterFunc(((gridCell.cell.column?.temp['reference-sequence'] != null) && (gridCell.cell.column?.temp['reference-sequence'] != ''))
|
|
140
|
+
? gridCell.cell.column.temp['reference-sequence'] : gridCell.cell.column.temp['current-word'] ?? '');
|
|
141
|
+
const monomerWidth = (gridCell.cell.column?.temp['monomer-width'] != null) ? gridCell.cell.column.temp['monomer-width'] : 'short';
|
|
142
|
+
let gapRenderer = 5;
|
|
135
143
|
|
|
144
|
+
let maxIndex = 0;
|
|
136
145
|
|
|
137
|
-
|
|
146
|
+
let maxLengthOfMonomer = 8;
|
|
147
|
+
|
|
148
|
+
if (monomerWidth === 'short') {
|
|
149
|
+
gapRenderer = 12;
|
|
150
|
+
maxLengthOfMonomer = 1;
|
|
151
|
+
}
|
|
138
152
|
|
|
139
153
|
let maxLengthWords: any = {};
|
|
140
154
|
if (gridCell.cell.column.getTag('.calculatedCellRender') !== splitLimit.toString()) {
|
|
141
155
|
let samples = 0;
|
|
142
156
|
while (samples < Math.min(gridCell.cell.column.length, 100)) {
|
|
143
|
-
|
|
144
|
-
|
|
157
|
+
const column = gridCell.cell.column.get(samples);
|
|
158
|
+
const subParts: string[] = splitterFunc(column);
|
|
145
159
|
subParts.forEach((amino, index) => {
|
|
146
|
-
|
|
147
|
-
if (textSize > (maxLengthWords[index] ?? 0))
|
|
160
|
+
const textSize = monomerToShortFunction(amino, maxLengthOfMonomer).length * 7 + gapRenderer;
|
|
161
|
+
if (textSize > (maxLengthWords[index] ?? 0))
|
|
148
162
|
maxLengthWords[index] = textSize;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
maxLengthWords['bio-maxIndex'] = index;
|
|
163
|
+
if (index > maxIndex) {
|
|
164
|
+
maxIndex = index;
|
|
152
165
|
}
|
|
153
166
|
});
|
|
154
167
|
samples += 1;
|
|
155
168
|
}
|
|
156
169
|
let minLength = 3 * 7;
|
|
157
|
-
for (let i = 0; i <=
|
|
170
|
+
for (let i = 0; i <= maxIndex; i++) {
|
|
158
171
|
if (maxLengthWords[i] < minLength) {
|
|
159
172
|
maxLengthWords[i] = minLength;
|
|
160
173
|
}
|
|
174
|
+
const maxLengthWordSum: any = {};
|
|
175
|
+
maxLengthWordSum[0] = maxLengthWords[0];
|
|
176
|
+
for (let i = 1; i <= maxIndex; i++) {
|
|
177
|
+
maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
|
|
178
|
+
}
|
|
179
|
+
gridCell.cell.column.temp['bio-sum-maxLengthWords'] = maxLengthWordSum;
|
|
180
|
+
gridCell.cell.column.temp['bio-maxIndex'] = maxIndex;
|
|
181
|
+
gridCell.cell.column.temp['bio-maxLengthWords'] = maxLengthWords;
|
|
182
|
+
gridCell.cell.column.setTag('.calculatedCellRender', splitLimit.toString());
|
|
161
183
|
}
|
|
162
|
-
let maxLengthWordSum: any = {};
|
|
163
|
-
maxLengthWordSum[0] = maxLengthWords[0];
|
|
164
|
-
for (let i = 1; i <= maxLengthWords['bio-maxIndex']; i++) {
|
|
165
|
-
maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
|
|
166
|
-
}
|
|
167
|
-
gridCell.cell.column.temp = {
|
|
168
|
-
'bio-sum-maxLengthWords': maxLengthWordSum,
|
|
169
|
-
'bio-maxIndex': maxLengthWords['bio-maxIndex'],
|
|
170
|
-
'bio-maxLengthWords': maxLengthWords
|
|
171
|
-
};
|
|
172
|
-
gridCell.cell.column.setTag('.calculatedCellRender', splitLimit.toString());
|
|
173
184
|
} else {
|
|
174
185
|
maxLengthWords = gridCell.cell.column.temp['bio-maxLengthWords'];
|
|
175
186
|
}
|
|
@@ -178,16 +189,15 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
178
189
|
let x1 = x;
|
|
179
190
|
let color = undefinedColor;
|
|
180
191
|
let drawStyle = DrawStyle.classic;
|
|
181
|
-
if (gridCell.cell.column.getTag('aligned').includes('MSA') && gridCell.cell.column.getTag('units') === 'separator')
|
|
192
|
+
if (gridCell.cell.column.getTag('aligned').includes('MSA') && gridCell.cell.column.getTag('units') === 'separator')
|
|
182
193
|
drawStyle = DrawStyle.MSA;
|
|
183
|
-
|
|
194
|
+
|
|
184
195
|
subParts.every((amino, index) => {
|
|
185
196
|
color = palette.get(amino);
|
|
186
197
|
g.fillStyle = undefinedColor;
|
|
187
198
|
let last = index === subParts.length - 1;
|
|
188
|
-
x1 = printLeftOrCentered(x1, y, w, h, g,
|
|
199
|
+
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell, referenceSequence, maxLengthOfMonomer);
|
|
189
200
|
return x1 - minDistanceRenderer - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x) <= gridCell.bounds.width;
|
|
190
|
-
|
|
191
201
|
});
|
|
192
202
|
|
|
193
203
|
g.restore();
|
|
@@ -196,13 +206,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
196
206
|
}
|
|
197
207
|
|
|
198
208
|
export class MonomerCellRenderer extends DG.GridCellRenderer {
|
|
199
|
-
get name(): string {return C.SEM_TYPES.MONOMER;}
|
|
209
|
+
get name(): string { return C.SEM_TYPES.MONOMER; }
|
|
200
210
|
|
|
201
|
-
get cellType(): string {return C.SEM_TYPES.MONOMER;}
|
|
211
|
+
get cellType(): string { return C.SEM_TYPES.MONOMER; }
|
|
202
212
|
|
|
203
|
-
get defaultHeight(): number {return 15;}
|
|
213
|
+
get defaultHeight(): number { return 15; }
|
|
204
214
|
|
|
205
|
-
get defaultWidth(): number {return 30;}
|
|
215
|
+
get defaultWidth(): number { return 30; }
|
|
206
216
|
|
|
207
217
|
/**
|
|
208
218
|
* Cell renderer function.
|
|
@@ -213,7 +223,7 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
|
|
|
213
223
|
* @param {number} w width of the cell.
|
|
214
224
|
* @param {number} h height of the cell.
|
|
215
225
|
* @param {DG.GridCell} gridCell Grid cell.
|
|
216
|
-
* @param {DG.GridCellStyle}
|
|
226
|
+
* @param {DG.GridCellStyle} _cellStyle Cell style.
|
|
217
227
|
*/
|
|
218
228
|
render(
|
|
219
229
|
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
|
|
@@ -249,7 +259,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
|
249
259
|
* @param {number} w width of the cell.
|
|
250
260
|
* @param {number} h height of the cell.
|
|
251
261
|
* @param {DG.GridCell} gridCell Grid cell.
|
|
252
|
-
* @param {DG.GridCellStyle}
|
|
262
|
+
* @param {DG.GridCellStyle} _cellStyle Cell style.
|
|
253
263
|
* @memberof AlignedSequenceDifferenceCellRenderer
|
|
254
264
|
*/
|
|
255
265
|
render(
|
|
@@ -261,7 +271,12 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
|
261
271
|
const separator = gridCell.tableColumn!.tags[C.TAGS.SEPARATOR];
|
|
262
272
|
const units: string = gridCell.tableColumn!.tags[DG.TAGS.UNITS];
|
|
263
273
|
w = getUpdatedWidth(grid, g, x, w);
|
|
264
|
-
|
|
274
|
+
//TODO: can this be replaced/merged with splitSequence?
|
|
275
|
+
const [s1, s2] = s.split('#');
|
|
276
|
+
const splitter = WebLogo.getSplitter(units, separator);
|
|
277
|
+
const subParts1 = splitter(s1);
|
|
278
|
+
const subParts2 = splitter(s2);
|
|
279
|
+
drawMoleculeDifferenceOnCanvas(g, x, y, w, h, subParts1, subParts2, units, separator);
|
|
265
280
|
}
|
|
266
281
|
}
|
|
267
282
|
|
|
@@ -271,17 +286,17 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
271
286
|
y: number,
|
|
272
287
|
w: number,
|
|
273
288
|
h: number,
|
|
274
|
-
|
|
289
|
+
subParts1: string [],
|
|
290
|
+
subParts2: string [],
|
|
275
291
|
units: string,
|
|
276
|
-
separator: string,
|
|
277
292
|
fullStringLength?: boolean,
|
|
278
|
-
molDifferences?:{[key: number]: HTMLCanvasElement}) {
|
|
293
|
+
molDifferences?: { [key: number]: HTMLCanvasElement }) {
|
|
279
294
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
295
|
+
if (subParts1.length !== subParts2.length) {
|
|
296
|
+
const emptyMonomersArray = new Array<string>(Math.abs(subParts1.length - subParts2.length)).fill('');
|
|
297
|
+
subParts1.length > subParts2.length ?
|
|
298
|
+
subParts2 = subParts2.concat(emptyMonomersArray) : subParts1 = subParts1.concat(emptyMonomersArray);
|
|
299
|
+
}
|
|
285
300
|
const textSize1 = g.measureText(processSequence(subParts1).join(''));
|
|
286
301
|
const textSize2 = g.measureText(processSequence(subParts2).join(''));
|
|
287
302
|
const textWidth = Math.max(textSize1.width, textSize2.width);
|
|
@@ -315,35 +330,33 @@ export function drawMoleculeDifferenceOnCanvas(
|
|
|
315
330
|
const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
|
|
316
331
|
const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
|
|
317
332
|
updatedX = Math.max(subX1, subX0);
|
|
318
|
-
if (molDifferences)
|
|
333
|
+
if (molDifferences)
|
|
319
334
|
molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
|
|
320
|
-
|
|
321
|
-
} else
|
|
322
|
-
updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5);
|
|
335
|
+
} else { updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5); }
|
|
323
336
|
updatedX += 4;
|
|
324
337
|
}
|
|
325
338
|
g.restore();
|
|
326
339
|
}
|
|
327
340
|
|
|
328
341
|
function createDifferenceCanvas(
|
|
329
|
-
amino1: string,
|
|
330
|
-
amino2: string,
|
|
331
|
-
color1: string,
|
|
332
|
-
color2: string,
|
|
342
|
+
amino1: string,
|
|
343
|
+
amino2: string,
|
|
344
|
+
color1: string,
|
|
345
|
+
color2: string,
|
|
333
346
|
y: number,
|
|
334
|
-
shift: number,
|
|
347
|
+
shift: number,
|
|
335
348
|
h: number): HTMLCanvasElement {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
+
const canvas = document.createElement('canvas');
|
|
350
|
+
const context = canvas.getContext('2d')!;
|
|
351
|
+
context.font = '12px monospace';
|
|
352
|
+
const width1 = context.measureText(processSequence([amino1]).join('')).width;
|
|
353
|
+
const width2 = context.measureText(processSequence([amino2]).join('')).width;
|
|
354
|
+
const width = Math.max(width1, width2);
|
|
355
|
+
canvas.height = h;
|
|
356
|
+
canvas.width = width + 4;
|
|
357
|
+
context.font = '12px monospace';
|
|
358
|
+
context.textBaseline = 'top';
|
|
359
|
+
printLeftOrCentered(0, y - shift, width, h, context, amino1, color1, 0, true);
|
|
360
|
+
printLeftOrCentered(0, y + shift, width, h, context, amino2, color2, 0, true);
|
|
361
|
+
return canvas;
|
|
349
362
|
}
|
|
@@ -3,6 +3,7 @@ import * as grok from 'datagrok-api/grok';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import {VdRegionType, VdRegion} from '@datagrok-libraries/bio/src/vd-regions';
|
|
6
|
+
import {IVdRegionsViewer} from '@datagrok-libraries/bio/src/viewers/vd-regions-viewer';
|
|
6
7
|
import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
7
8
|
|
|
8
9
|
const vrt = VdRegionType;
|
|
@@ -36,7 +37,7 @@ const vrt = VdRegionType;
|
|
|
36
37
|
/** Viewer with tabs based on description of chain regions.
|
|
37
38
|
* Used to define regions of an immunoglobulin LC.
|
|
38
39
|
*/
|
|
39
|
-
export class VdRegionsViewer extends DG.JsViewer {
|
|
40
|
+
export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
40
41
|
// private regionsDf: DG.DataFrame;
|
|
41
42
|
private regionsFg: DG.FilterGroup | null = null;
|
|
42
43
|
// private regionsTV: DG.TableView;
|
|
@@ -4,6 +4,64 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import {getMolfilesFromSingleSeq, HELM_CORE_LIB_FILENAME} from '../utils/utils';
|
|
5
5
|
import {getMacroMol} from '../utils/atomic-works';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @export
|
|
9
|
+
* @param {DG.Column} col macromolecule cell.
|
|
10
|
+
* @return {Promise<DG.Widget>} Widget.
|
|
11
|
+
*/
|
|
12
|
+
export function getMacroMolColumnPropertyPanel(col: DG.Column): DG.Widget {
|
|
13
|
+
const NONE = 'None';
|
|
14
|
+
const scaffoldColName = 'short';
|
|
15
|
+
|
|
16
|
+
// TODO: replace with an efficient version, bySemTypesExact won't help; GROK-8094
|
|
17
|
+
const columnsList = Array.from(col.dataFrame.columns as any).filter(
|
|
18
|
+
(c: any) => c.semType === DG.SEMTYPE.MOLECULE).map((c: any) => c.name);
|
|
19
|
+
const columnsSet = new Set(columnsList);
|
|
20
|
+
columnsSet.delete(col.name);
|
|
21
|
+
|
|
22
|
+
const monomerWidth = ui.choiceInput('Monomer width',
|
|
23
|
+
(col?.temp['monomer-width'] != null) ? col.temp['monomer-width'] : 'short',
|
|
24
|
+
['short', 'long'],
|
|
25
|
+
(s: string) => {
|
|
26
|
+
col.temp['monomer-width'] = s;
|
|
27
|
+
col.setTag('.calculatedCellRender', '0');
|
|
28
|
+
col.dataFrame.fireValuesChanged();
|
|
29
|
+
});
|
|
30
|
+
monomerWidth.setTooltip('In short mode, only the first character should be visible, followed by .. if there are more characters');
|
|
31
|
+
|
|
32
|
+
const colorCode = ui.boolInput('Color code',
|
|
33
|
+
(col?.temp['color-code'] != null) ? col.temp['color-code'] : true,
|
|
34
|
+
(v: boolean) => {
|
|
35
|
+
col.temp['color-code'] = v;
|
|
36
|
+
col.dataFrame.fireValuesChanged();
|
|
37
|
+
});
|
|
38
|
+
colorCode.setTooltip('Color code');
|
|
39
|
+
|
|
40
|
+
const referenceSequence = ui.stringInput('Reference sequence', (col?.temp['reference-sequence'] != null) ? col?.temp['reference-sequence'] : '', (v: string) => {
|
|
41
|
+
col.temp['reference-sequence'] = v;
|
|
42
|
+
col.dataFrame.fireValuesChanged();
|
|
43
|
+
});
|
|
44
|
+
referenceSequence.setTooltip('Reference sequence is not empty, then the sequence will be render ' + '\n' +
|
|
45
|
+
'as a difference from the reference sequence');
|
|
46
|
+
|
|
47
|
+
const compareWithCurrent = ui.boolInput('Compare with current',
|
|
48
|
+
(col?.temp['compare-with-current'] != null) ? col.temp['compare-with-current'] : true,
|
|
49
|
+
(v: boolean) => {
|
|
50
|
+
col.temp['compare-with-current'] = v;
|
|
51
|
+
col.dataFrame.fireValuesChanged();
|
|
52
|
+
});
|
|
53
|
+
compareWithCurrent.setTooltip('When on, all sequences get rendered in the "diff" mode');
|
|
54
|
+
|
|
55
|
+
const rdKitInputs = ui.inputs([
|
|
56
|
+
monomerWidth,
|
|
57
|
+
colorCode,
|
|
58
|
+
referenceSequence,
|
|
59
|
+
compareWithCurrent
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
return new DG.Widget(rdKitInputs);
|
|
63
|
+
}
|
|
64
|
+
|
|
7
65
|
/**
|
|
8
66
|
* 3D representation widget of macromolecule.
|
|
9
67
|
*
|