@datagrok/bio 2.9.0 → 2.10.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.
@@ -143,8 +143,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
143
143
  // Cell renderer settings
144
144
  const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
145
145
  const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
146
- if (monomerWidth === 'short')
147
- maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties.MaxMonomerLength;
146
+ if (monomerWidth === 'short') {
147
+ // Renderer can start to work before Bio package initialized, in that time _package.properties is null.
148
+ // TODO: Render function is available but package init method is not completed
149
+ maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties?.MaxMonomerLength ?? 4;
150
+ }
148
151
 
149
152
 
150
153
  let seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
@@ -206,36 +209,6 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
206
209
  ((tempReferenceSequence != null) && (tempReferenceSequence != '')) ?
207
210
  tempReferenceSequence : tempCurrentWord ?? '');
208
211
 
209
- // let maxLengthWords: { [pos: number]: number } = {};
210
- // if (tableCol.getTag(rndrTAGS.calculatedCellRender) !== splitLimit.toString()) {
211
- // let sampleCount = 0;
212
- // while (sampleCount < Math.min(tableCol.length, 100)) {
213
- // const rowIdx: number = sampleCount;
214
- // const column = tableCol.get(rowIdx);
215
- // const subParts: string[] = splitterFunc(column);
216
- // for (const [index, amino] of subParts.entries()) {
217
- // const textSize = monomerToShortFunction(amino, maxLengthOfMonomer).length * 7 + gapRenderer;
218
- // if (textSize > (maxLengthWords[index] ?? 0))
219
- // maxLengthWords[index] = textSize;
220
- // if (index > maxIndex) maxIndex = index;
221
- // }
222
- // sampleCount += 1;
223
- // }
224
- // const minLength = 3 * 7;
225
- // for (let i = 0; i <= maxIndex; i++) {
226
- // if (maxLengthWords[i] < minLength) maxLengthWords[i] = minLength;
227
- // const maxLengthWordSum: { [pos: number]: number } = {};
228
- // maxLengthWordSum[0] = maxLengthWords[0];
229
- // for (let i = 1; i <= maxIndex; i++) maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
230
- // colTemp[tempTAGS.bioSumMaxLengthWords] = maxLengthWordSum;
231
- // colTemp[tempTAGS.bioMaxIndex] = maxIndex;
232
- // colTemp[tempTAGS.bioMaxLengthWords] = maxLengthWords;
233
- // tableCol.setTag(rndrTAGS.calculatedCellRender, splitLimit.toString());
234
- // }
235
- // } else {
236
- // maxLengthWords = colTemp[tempTAGS.bioMaxLengthWords];
237
- // }
238
-
239
212
  const subParts: ISeqSplitted = splitterFunc(value);
240
213
  /* let x1 = x; */
241
214
  let color = undefinedColor;
@@ -4,7 +4,6 @@ import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
6
6
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
- import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
8
7
 
9
8
  import {_package} from '../package';
10
9
 
@@ -15,9 +14,9 @@ export function addCopyMenuUI(cell: DG.Cell, menu: DG.Menu): void {
15
14
 
16
15
  menu.group('Copy')
17
16
  .items(tgtNotationList, (tgtNotation) => {
18
- const nc = new NotationConverter(cell.column);
17
+ const ncUH = UnitsHandler.getOrCreate(cell.column);
19
18
  const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.DefaultSeparator : undefined;
20
- const converter = nc.getConverter(tgtNotation as NOTATION, separator);
19
+ const converter = ncUH.getConverter(tgtNotation as NOTATION, separator);
21
20
  const tgtSeq = converter(cell.value);
22
21
 
23
22
  if (!navigator.clipboard) {
@@ -5,7 +5,6 @@ import * as grok from 'datagrok-api/grok';
5
5
  import $ from 'cash-dom';
6
6
  import {Subscription} from 'rxjs';
7
7
  import {NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
- import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
9
8
  import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
10
9
  import {expect} from '@datagrok-libraries/utils/src/test';
11
10
 
@@ -22,8 +21,8 @@ export function convert(col?: DG.Column): void {
22
21
  let tgtCol = col ?? grok.shell.t.columns.bySemType('Macromolecule')!;
23
22
  if (!tgtCol)
24
23
  throw new Error('No column with Macromolecule semantic type found');
25
- let converter = new NotationConverter(tgtCol);
26
- let currentNotation: NOTATION = converter.notation;
24
+ let converterUH = UnitsHandler.getOrCreate(tgtCol);
25
+ let currentNotation: NOTATION = converterUH.notation;
27
26
  const dialogHeader = ui.divText(
28
27
  'Current notation: ' + currentNotation,
29
28
  {
@@ -47,8 +46,8 @@ export function convert(col?: DG.Column): void {
47
46
  }
48
47
 
49
48
  tgtCol = newCol;
50
- converter = new NotationConverter(tgtCol);
51
- currentNotation = converter.notation;
49
+ converterUH = UnitsHandler.getOrCreate(tgtCol);
50
+ currentNotation = converterUH.notation;
52
51
  if (currentNotation === NOTATION.HELM)
53
52
  separatorInput.value = '/'; // helm monomers can have - in the name like D-aThr;
54
53
  dialogHeader.textContent = 'Current notation: ' + currentNotation;
@@ -117,8 +116,8 @@ export function convert(col?: DG.Column): void {
117
116
  * @param {string | null} separator Separator for SEPARATOR notation
118
117
  */
119
118
  export async function convertDo(srcCol: DG.Column, targetNotation: NOTATION, separator?: string): Promise<DG.Column> {
120
- const converter = new NotationConverter(srcCol);
121
- const newColumn = converter.convert(targetNotation, separator);
119
+ const converterUH = UnitsHandler.getOrCreate(srcCol);
120
+ const newColumn = converterUH.convert(targetNotation, separator);
122
121
  srcCol.dataFrame.columns.add(newColumn);
123
122
 
124
123
  // Call detector directly to escape some error on detectSemanticTypes
@@ -0,0 +1,241 @@
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
+ import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
+
7
+ export interface GetRegionParams {
8
+ table: DG.DataFrame,
9
+ sequence: DG.Column<string>,
10
+ start: string | null,
11
+ end: string | null,
12
+ /** Name for the column with sequence of the region */ name: string | null,
13
+ }
14
+
15
+ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
16
+ import {_package} from '../package';
17
+
18
+ export interface SeqRegion {
19
+ name: string,
20
+ description: string,
21
+ start: string,
22
+ end: string,
23
+ }
24
+
25
+ export class GetRegionFuncEditor {
26
+ inputs = new class {
27
+ table: DG.InputBase<DG.DataFrame | null>;
28
+ sequence: DG.InputBase<DG.Column | null>;
29
+ region: DG.InputBase<SeqRegion>;
30
+ start: DG.InputBase<string>;
31
+ end: DG.InputBase<string>;
32
+ name: DG.InputBase;
33
+ }();
34
+
35
+ constructor(
36
+ private readonly call: DG.FuncCall
37
+ ) {
38
+ const getDesc = (paramName: string) => this.call.inputParams[paramName].property.description;
39
+
40
+ this.inputs.table = ui.tableInput('Table',
41
+ this.call.inputParams['table'].value ?? grok.shell.tv.dataFrame, undefined,
42
+ () => {});
43
+
44
+ const seqColValue = this.call.inputParams['sequence'].value ??
45
+ this.inputs.table.value!.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
46
+ const seqColOptions = {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE};
47
+ this.inputs.sequence = ui.columnInput('Sequence', grok.shell.tv.dataFrame, seqColValue,
48
+ this.sequenceInputChanged.bind(this), seqColOptions);
49
+ this.inputs.start = ui.choiceInput(
50
+ 'Start', undefined, [], this.startInputChanged.bind(this)) as unknown as DG.InputBase<string>;
51
+ this.inputs.end = ui.choiceInput(
52
+ 'End', undefined, [], this.endInputChanged.bind(this)) as unknown as DG.InputBase<string>;
53
+
54
+ this.inputs.region = ui.choiceInput<SeqRegion>('Region', null as unknown as SeqRegion, [],
55
+ this.regionInputChanged.bind(this)) as DG.InputBase<SeqRegion>;
56
+
57
+ this.inputs.name = ui.stringInput('Name', '', () => {},
58
+ {placeholder: this.getDefaultName()});
59
+
60
+ // tooltips
61
+ for (const paramName in this.call.inputParams) {
62
+ // @ts-ignore
63
+ ui.tooltip.bind(this.inputs[paramName].captionLabel, getDesc(paramName));
64
+ }
65
+
66
+ // initial
67
+ this.sequenceInputChanged();
68
+ }
69
+
70
+ private sequenceInputChanged(): void {
71
+ const seqCol = this.inputs.sequence.value;
72
+ const uh = seqCol ? UnitsHandler.getOrCreate(seqCol) : null;
73
+ this.updateRegionItems();
74
+ this.updateStartEndInputItems();
75
+ this.updateRegion(true);
76
+ this.updateNameInputPlaceholder();
77
+ }
78
+
79
+ private fixRegion: boolean = false;
80
+
81
+ private regionInputChanged(): void {
82
+ this.fixRegion = true;
83
+ try {
84
+ const regJsonStr = this.inputs.region.stringValue;
85
+ const reg: SeqRegion | null = regJsonStr ? JSON.parse(regJsonStr) as SeqRegion : null;
86
+
87
+ if (reg !== null) {
88
+ this.inputs.start.value = reg?.start;
89
+ this.inputs.end.value = reg?.end;
90
+ } else {
91
+ const uh = UnitsHandler.getOrCreate(this.inputs.sequence.value!);
92
+ this.inputs.start.value = uh.posList[0];
93
+ this.inputs.end.value = uh.posList[uh.posList.length - 1];
94
+ }
95
+ } finally {
96
+ this.fixRegion = false;
97
+ }
98
+ }
99
+
100
+ private startInputChanged(): void {
101
+ this.updateRegion(false);
102
+ this.updateNameInputPlaceholder();
103
+ }
104
+
105
+ private endInputChanged(): void {
106
+ this.updateRegion(false);
107
+ this.updateNameInputPlaceholder();
108
+ }
109
+
110
+ private updateStartEndInputItems(): void {
111
+ const seqCol = this.inputs.sequence.value;
112
+ const uh = seqCol ? UnitsHandler.getOrCreate(seqCol) : null;
113
+
114
+ const startSE = (this.inputs.start.input as HTMLSelectElement);
115
+ const endSE = (this.inputs.end.input as HTMLSelectElement);
116
+ for (let i = startSE.options.length - 1; i >= 0; --i) startSE.options.remove(i);
117
+ for (let i = endSE.options.length - 1; i >= 0; --i) endSE.options.remove(i);
118
+ for (const pos of uh?.posList ?? []) {
119
+ const startPosOE = document.createElement('option');
120
+ const endPosOE = document.createElement('option');
121
+ startPosOE.text = endPosOE.text = pos;
122
+ startPosOE.value = endPosOE.value = pos;
123
+ startSE.options.add(startPosOE);
124
+ endSE.options.add(endPosOE);
125
+ }
126
+ startSE.value = uh?.posList[0] ?? '';
127
+ endSE.value = uh?.posList[uh?.posList.length - 1] ?? '';
128
+ }
129
+
130
+ private updateRegionItems(): void {
131
+ const seqCol = this.inputs.sequence.value;
132
+ const regionsTagTxt: string | null = seqCol ? seqCol.getTag(bioTAGS.regions) : null;
133
+ const regionList: SeqRegion[] | null = regionsTagTxt ? JSON.parse(regionsTagTxt) : null;
134
+
135
+ const regionSE = (this.inputs.region.input as HTMLSelectElement);
136
+ for (let i = regionSE.options.length - 1; i >= 0; --i) regionSE.options.remove(i);
137
+
138
+ const nullOE = document.createElement('option');
139
+ nullOE.text = '';
140
+ nullOE.value = JSON.stringify(null);
141
+ regionSE.options.add(nullOE);
142
+
143
+ if (regionList != null) {
144
+ this.inputs.region.root.style.removeProperty('display');
145
+ for (const region of regionList) {
146
+ const regionOE = document.createElement('option');
147
+ regionOE.text = `${region.name}: ${region.start}-${region.end}`;
148
+ regionOE.value = JSON.stringify(region);
149
+ regionSE.options.add(regionOE);
150
+ }
151
+ } else {
152
+ this.inputs.region.root.style.display = 'none';
153
+ }
154
+ }
155
+
156
+ private updateRegion(reset: boolean): void {
157
+ const startPos: string = this.inputs.start.stringValue ?? '';
158
+ const endPos: string = this.inputs.end.stringValue ?? '';
159
+
160
+ if (!this.fixRegion) {
161
+ const regionSE = (this.inputs.region.input as HTMLSelectElement);
162
+ regionSE.selectedIndex = -1;
163
+ for (let i = regionSE.options.length - 1; i >= 0; --i) {
164
+ const regionOE = regionSE.options[i];
165
+ const reg: SeqRegion = JSON.parse(regionOE.value);
166
+ if (reg && startPos === reg.start && endPos === reg.end) regionSE.selectedIndex = i;
167
+ }
168
+ }
169
+ }
170
+
171
+ private updateNameInputPlaceholder(): void {
172
+ // @ts-ignore
173
+ this.inputs.name.input.attributes['placeholder'].value = this.getDefaultName();
174
+ }
175
+
176
+ private getDefaultName(): string {
177
+ const regionJsonStr = this.inputs.region.stringValue;
178
+ const reg: SeqRegion | null = regionJsonStr ? JSON.parse(regionJsonStr) : null;
179
+
180
+ const seqCol: DG.Column<string> = this.inputs.sequence.value!;
181
+
182
+ const startPos: string = this.inputs.start.stringValue ?? '';
183
+ const endPos: string = this.inputs.end.stringValue ?? '';
184
+
185
+ return reg != null ? `${seqCol.name}(${reg.name}): ${reg.start}-${reg.end}` :
186
+ `${seqCol?.name}: (${startPos}-${endPos})`;
187
+ }
188
+
189
+ private getParams(): {} {
190
+ return {
191
+ table: this.inputs.table.value!,
192
+ sequence: this.inputs.sequence.value!,
193
+ start: this.getStart(),
194
+ end: this.getEnd(),
195
+ name: this.getName() ?? this.getDefaultName(),
196
+ };
197
+ }
198
+
199
+ private getStart(): string | null {
200
+ return this.inputs.start.stringValue;
201
+ }
202
+
203
+ private getEnd(): string | null {
204
+ return this.inputs.end.stringValue;
205
+ }
206
+
207
+ private getName(): string | null {
208
+ const str = this.inputs.name.stringValue;
209
+ return str == '' ? null : str;
210
+ }
211
+
212
+ // -- UI --
213
+
214
+ public dialog(): void {
215
+ const inputsForm = ui.inputs(Object.values(this.inputs), {style: {minWidth: '320px'}});
216
+ ui.dialog({title: 'Get Region'})
217
+ .add(inputsForm)
218
+ .onOK(async () => {
219
+ (async () => {
220
+ const callParams = this.getParams();
221
+ await this.call.func.prepare(callParams).call(true);
222
+ })()
223
+ .catch((err: any) => { _package.handleErrorUI(err); });
224
+ })
225
+ .show();
226
+ }
227
+
228
+ public widget(): DG.Widget {
229
+ const inputsForm = ui.inputs(Object.entries(this.inputs)
230
+ .filter(([inputName, input]) => !['table', 'sequence'].includes(inputName))
231
+ .map(([inputName, input]) => input));
232
+ const doBtn = ui.button('Get Region', () => {
233
+ (async () => {
234
+ const callParams = this.getParams();
235
+ await this.call.func.prepare(callParams).call(true);
236
+ })()
237
+ .catch((err: any) => { _package.handleErrorUI(err); });
238
+ });
239
+ return DG.Widget.fromRoot(ui.divV([inputsForm, ui.div(doBtn)]));
240
+ }
241
+ }
@@ -0,0 +1,65 @@
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
+ import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
+ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
7
+ import {getRegion} from '../package';
8
+ import {TaskBarProgressIndicator} from 'datagrok-api/dg';
9
+
10
+ export function getRegionUI(col: DG.Column<string>): void {
11
+ const uh = UnitsHandler.getOrCreate(col);
12
+
13
+ const nameInput = ui.stringInput('Name', '');
14
+ const startPositionInput = ui.choiceInput('Start Position', uh.posList[0], uh.posList,
15
+ () => { /* TODO: update name placeholder with getDefaultName() */ });
16
+ const endPositionInput = ui.choiceInput('End Position', uh.posList[uh.posList.length], uh.posList,
17
+ () => { /* TODO: update name placeholder with getDefaultName() */ });
18
+
19
+ const getDefaultName = (): string => {
20
+ return `${col.name}:${startPositionInput.value}-${endPositionInput.value}`;
21
+ };
22
+
23
+ ui.dialog({title: 'Get Region'}).add(ui.inputs([
24
+ nameInput,
25
+ startPositionInput,
26
+ endPositionInput,
27
+ ])).onOK(() => {
28
+ const pi = TaskBarProgressIndicator.create('Getting region...');
29
+ try {
30
+ const name: string = nameInput.value ?? getDefaultName();
31
+ const regCol = getRegionDo(col, name, startPositionInput.value, endPositionInput.value);
32
+ col.dataFrame.columns.add(regCol);
33
+ regCol.setTag(DG.TAGS.CELL_RENDERER, 'sequence');
34
+ } catch (err: any) {
35
+ grok.shell.error(err.toString());
36
+ } finally { pi.close(); }
37
+ });
38
+ }
39
+
40
+ /** {@link startPosName} and {@link endPosName} are according positionNames tag (or default ['1', '2',...]) */
41
+ export function getRegionDo(
42
+ col: DG.Column<string>, startPosName: string | null, endPosName: string | null, name: string | null
43
+ ): DG.Column<string> {
44
+ const uh = UnitsHandler.getOrCreate(col);
45
+
46
+ let startPosIdx: number | null = null;
47
+ let endPosIdx: number | null = null;
48
+
49
+ for (let posJ: number = 0; posJ < uh.posList.length; ++posJ) {
50
+ if (uh.posList[posJ] == startPosName) startPosIdx = posJ;
51
+ if (uh.posList[posJ] == endPosName) endPosIdx = posJ;
52
+ }
53
+ if (startPosIdx === null && startPosName !== null)
54
+ throw new Error(`Start position ${startPosName} not found.`);
55
+ if (endPosIdx === null && endPosName !== null)
56
+ throw new Error(`End position ${endPosName} not found.`);
57
+
58
+ if (uh.posList.length < endPosIdx!)
59
+ throw new Error(`End position ${endPosIdx} exceeds positions length`);
60
+
61
+ const regColName: string = !!name ? name : `${col.name}: (${startPosName ?? ''}-${endPosName ?? ''})`;
62
+
63
+ const regCol = uh.getRegion(startPosIdx, endPosIdx, regColName);
64
+ return regCol;
65
+ }
@@ -3,15 +3,19 @@ import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
+ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
7
+ import {ColumnInputOptions} from '@datagrok-libraries/utils/src/type-declarations';
8
+
6
9
  import {runKalign} from './multiple-sequence-alignment';
7
10
  import {pepseaMethods, runPepsea} from './pepsea';
8
11
  import {checkInputColumnUI} from './check-input-column';
9
- import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
10
- import {_package} from '../package';
11
12
  import {multipleSequenceAlginmentUIOptions} from './types';
12
13
  import {kalignVersion, msaDefaultOptions} from './constants';
14
+
15
+ import {_package} from '../package';
16
+
13
17
  import '../../css/msa.css';
14
- import {ColumnInputOptions} from '@datagrok-libraries/utils/src/type-declarations';
18
+
15
19
  export class MsaWarning extends Error {
16
20
  constructor(message: string, options?: ErrorOptions) {
17
21
  super(message, options);
@@ -66,12 +70,12 @@ export async function multipleSequenceAlignmentUI(
66
70
  //TODO: remove when the new version of datagrok-api is available
67
71
  //TODO: allow only macromolecule colums to be chosen
68
72
  const colInput = ui.columnInput('Sequence', table, seqCol, async () => {
69
- performAlignment = await onColInputChange(
70
- colInput.value, table, pepseaInputRootStyles, kalignInputRootStyles,
71
- methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
72
- );
73
- //@ts-ignore
74
- }, {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE} as ColumnInputOptions
73
+ performAlignment = await onColInputChange(
74
+ colInput.value, table, pepseaInputRootStyles, kalignInputRootStyles,
75
+ methodInput, clustersColInput, gapOpenInput, gapExtendInput, terminalGapInput,
76
+ );
77
+ //@ts-ignore
78
+ }, {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE} as ColumnInputOptions
75
79
  ) as DG.InputBase<DG.Column<string>>;
76
80
  colInput.setTooltip('Sequences column to use for alignment');
77
81
  const clustersColInput = ui.columnInput('Clusters', table, options.clustersCol);
@@ -100,7 +104,7 @@ export async function multipleSequenceAlignmentUI(
100
104
  }
101
105
 
102
106
  async function onDialogOk(
103
- colInput: DG.InputBase< DG.Column<any>>,
107
+ colInput: DG.InputBase<DG.Column<any>>,
104
108
  table: DG.DataFrame,
105
109
  performAlignment: (() => Promise<DG.Column<string> | null>) | undefined,
106
110
  resolve: (value: DG.Column<any>) => void,
@@ -151,9 +155,9 @@ async function onColInputChange(
151
155
  gapOpenInput.value = null;
152
156
  gapExtendInput.value = null;
153
157
  terminalGapInput.value = null;
154
- const potentialColNC = new NotationConverter(col);
155
- const performCol: DG.Column<string> = potentialColNC.isFasta() ? col :
156
- potentialColNC.convert(NOTATION.FASTA);
158
+ const potentialColUH = UnitsHandler.getOrCreate(col);
159
+ const performCol: DG.Column<string> = potentialColUH.isFasta() ? col :
160
+ potentialColUH.convert(NOTATION.FASTA);
157
161
  return async () => await runKalign(performCol, false, unusedName, clustersColInput.value);
158
162
  } else if (checkInputColumnUI(col, col.name,
159
163
  [NOTATION.HELM], [], false)
@@ -163,18 +167,18 @@ async function onColInputChange(
163
167
  gapExtendInput.value ??= msaDefaultOptions.pepsea.gapExtend;
164
168
 
165
169
  return async () => await runPepsea(col, unusedName, methodInput.value!,
166
- gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
170
+ gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
167
171
  } else if (checkInputColumnUI(col, col.name, [NOTATION.SEPARATOR], [ALPHABET.UN], false)) {
168
172
  //if the column is separator with unknown alphabet, it might be helm. check if it can be converted to helm
169
- const potentialColNC = new NotationConverter(col);
170
- const helmCol = potentialColNC.convert(NOTATION.HELM);
173
+ const potentialColUH = UnitsHandler.getOrCreate(col);
174
+ const helmCol = potentialColUH.convert(NOTATION.HELM);
171
175
  switchDialog(pepseaInputRootStyles, kalignInputRootStyles, 'pepsea');
172
176
  gapOpenInput.value ??= msaDefaultOptions.pepsea.gapOpen;
173
177
  gapExtendInput.value ??= msaDefaultOptions.pepsea.gapExtend;
174
178
  // convert to helm and assign alignment function to PepSea
175
179
 
176
180
  return async () => await runPepsea(helmCol, unusedName, methodInput.value!,
177
- gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
181
+ gapOpenInput.value!, gapExtendInput.value!, clustersColInput.value);
178
182
  } else {
179
183
  gapOpenInput.value = null;
180
184
  gapExtendInput.value = null;
@@ -8,14 +8,15 @@ import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
8
8
  import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
9
9
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
10
10
  import {
11
- monomerToShort, pickUpPalette, pickUpSeqCol, TAGS as bioTAGS
11
+ monomerToShort, pickUpPalette, pickUpSeqCol, TAGS as bioTAGS, positionSeparator
12
12
  } from '@datagrok-libraries/bio/src/utils/macromolecule';
13
13
  import {
14
- FilterSources, HorizontalAlignments, IWebLogoViewer, PositionHeight, PositionMarginStates, positionSeparator,
15
- TAGS as wlTAGS, VerticalAlignments, WebLogoProps, WebLogoPropsDefault
14
+ FilterSources, HorizontalAlignments, IWebLogoViewer, PositionHeight, PositionMarginStates,
15
+ VerticalAlignments, WebLogoProps, WebLogoPropsDefault
16
16
  } from '@datagrok-libraries/bio/src/viewers/web-logo';
17
17
  import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
18
18
  import {intToHtmlA} from '@datagrok-libraries/utils/src/color';
19
+ import {TAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
19
20
  import {ISeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
20
21
 
21
22
  import {_package} from '../package';
@@ -560,8 +561,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
560
561
  }).reduce((max, l) => Math.max(max, l), 0);
561
562
 
562
563
  /** positionNames and positionLabel can be set up through the column's tags only */
563
- const positionNamesTxt = this.seqCol.getTag(wlTAGS.positionNames);
564
- const positionLabelsTxt = this.seqCol.getTag(wlTAGS.positionLabels);
564
+ const positionNamesTxt = this.seqCol.getTag(TAGS.positionNames);
565
+ const positionLabelsTxt = this.seqCol.getTag(TAGS.positionLabels);
565
566
  this.positionNames = !!positionNamesTxt ? positionNamesTxt.split(positionSeparator).map((v) => v.trim()) :
566
567
  [...Array(maxLength).keys()].map((jPos) => `${jPos + 1}`)/* fallback if tag is not provided */;
567
568
  this.positionLabels = !!positionLabelsTxt ? positionLabelsTxt.split(positionSeparator).map((v) => v.trim()) :
@@ -1034,7 +1035,8 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
1034
1035
  min: this.slider.min, max: this.slider.max,
1035
1036
  maxRange: this.slider.maxRange
1036
1037
  };
1037
- _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>.sliderOnValuesChanged( ${JSON.stringify(val)} ), start`);
1038
+ _package.logger.debug(
1039
+ `Bio: WebLogoViewer<${this.viewerId}>.sliderOnValuesChanged( ${JSON.stringify(val)} ), start`);
1038
1040
  this.render(WlRenderLevel.Layout, 'sliderOnValuesChanged').then(() => {});
1039
1041
  } catch (err: any) {
1040
1042
  const errMsg = errorToConsole(err);