@datagrok/bio 2.0.17 → 2.0.19

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.
@@ -1,11 +1,12 @@
1
- import {after, before, category, test, expect, expectArray, expectObject} from '@datagrok-libraries/utils/src/test';
2
-
3
1
  import * as grok from 'datagrok-api/grok';
4
2
  import * as ui from 'datagrok-api/ui';
5
3
  import * as DG from 'datagrok-api/dg';
6
- import {WebLogo, SplitterFunc} from '@datagrok-libraries/bio/src/viewers/web-logo';
7
- import {splitToMonomers, _package, getHelmMonomers} from '../package';
4
+ import * as bio from '@datagrok-libraries/bio';
5
+
6
+ import {after, before, category, test, expect, expectArray, expectObject} from '@datagrok-libraries/utils/src/test';
8
7
  import * as C from '../utils/constants';
8
+ import {splitToMonomers, _package, getHelmMonomers} from '../package';
9
+
9
10
 
10
11
  category('splitters', () => {
11
12
  let tvList: DG.TableView[];
@@ -121,13 +122,13 @@ PEPTIDE1{hHis.Aca.Cys_SEt}$$$,5.72388
121
122
  });
122
123
 
123
124
  export async function _testFastaSplitter(src: string, tgt: string[]) {
124
- const res: string[] = WebLogo.splitterAsFasta(src);
125
+ const res: string[] = bio.splitterAsFasta(src);
125
126
  console.debug(`Bio: tests: splitters: src=${JSON.stringify(src)}, res=${JSON.stringify(res)} .`);
126
127
  expectArray(res, tgt);
127
128
  }
128
129
 
129
130
  export async function _testHelmSplitter(src: string, tgt: string[]) {
130
- const res: string[] = WebLogo.splitterAsHelm(src);
131
+ const res: string[] = bio.splitterAsHelm(src);
131
132
  console.debug(`Bio: tests: splitters: src=${JSON.stringify(src)}, res=${JSON.stringify(res)} .`);
132
133
  expectArray(res, tgt);
133
134
  }
@@ -1,31 +1,26 @@
1
- import * as C from './constants';
2
- import * as DG from 'datagrok-api/dg';
3
- import {AminoacidsPalettes} from '@datagrok-libraries/bio/src/aminoacids';
4
- import {NucleotidesPalettes} from '@datagrok-libraries/bio/src/nucleotides';
5
- import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
6
- import {SplitterFunc, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
7
- import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
1
+ import * as grok from 'datagrok-api/grok';
8
2
  import * as ui from 'datagrok-api/ui';
9
- import {printLeftOrCentered, DrawStyle} from '@datagrok-libraries/bio/src/utils/cell-renderer';
10
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
3
+ import * as DG from 'datagrok-api/dg';
4
+ import * as bio from '@datagrok-libraries/bio';
5
+ import * as C from './constants';
11
6
 
12
7
  const undefinedColor = 'rgb(100,100,100)';
13
- const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string = WebLogo.monomerToShort;
8
+ const monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string = bio.monomerToShort;
14
9
 
15
10
 
16
- function getPaletteByType(paletteType: string): SeqPalette {
11
+ function getPaletteByType(paletteType: string): bio.SeqPalette {
17
12
  switch (paletteType) {
18
13
  case 'PT':
19
- return AminoacidsPalettes.GrokGroups;
14
+ return bio.AminoacidsPalettes.GrokGroups;
20
15
  case 'NT':
21
- return NucleotidesPalettes.Chromatogram;
16
+ return bio.NucleotidesPalettes.Chromatogram;
22
17
  case 'DNA':
23
- return NucleotidesPalettes.Chromatogram;
18
+ return bio.NucleotidesPalettes.Chromatogram;
24
19
  case 'RNA':
25
- return NucleotidesPalettes.Chromatogram;
20
+ return bio.NucleotidesPalettes.Chromatogram;
26
21
  // other
27
22
  default:
28
- return UnknownSeqPalettes.Color;
23
+ return bio.UnknownSeqPalettes.Color;
29
24
  }
30
25
  }
31
26
 
@@ -66,7 +61,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
66
61
  }
67
62
 
68
63
  onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
69
- if (gridCell.cell.column.getTag(UnitsHandler.TAGS.aligned) !== 'SEQ.MSA')
64
+ if (gridCell.cell.column.getTag(bio.UnitsHandler.TAGS.aligned) !== 'SEQ.MSA')
70
65
  return;
71
66
 
72
67
  const maxLengthWordsSum = gridCell.cell.column.temp['bio-sum-maxLengthWords'];
@@ -94,7 +89,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
94
89
  }
95
90
  left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
96
91
  const separator = gridCell.cell.column.getTag('separator') ?? '';
97
- const splitterFunc: SplitterFunc = WebLogo.getSplitter('separator', separator);
92
+ const splitterFunc: bio.SplitterFunc = bio.getSplitter('separator', separator);
98
93
  const subParts: string[] = splitterFunc(gridCell.cell.value);
99
94
  (((subParts[left]?.length ?? 0) > 0)) ?
100
95
  ui.tooltip.show(ui.div(subParts[left]), e.x + 16, e.y + 16) : ui.tooltip.hide();
@@ -135,7 +130,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
135
130
 
136
131
  const separator = gridCell.cell.column.getTag('separator') ?? '';
137
132
  const splitLimit = gridCell.bounds.width / 5;
138
- const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, separator, splitLimit);
133
+ const splitterFunc: bio.SplitterFunc = bio.getSplitter(units, separator, splitLimit);
139
134
  const referenceSequence: string[] = splitterFunc(((gridCell.cell.column?.temp['reference-sequence'] != null) && (gridCell.cell.column?.temp['reference-sequence'] != ''))
140
135
  ? gridCell.cell.column.temp['reference-sequence'] : gridCell.cell.column.temp['current-word'] ?? '');
141
136
  const monomerWidth = (gridCell.cell.column?.temp['monomer-width'] != null) ? gridCell.cell.column.temp['monomer-width'] : 'short';
@@ -188,15 +183,15 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
188
183
  const subParts: string[] = splitterFunc(cell.value);
189
184
  let x1 = x;
190
185
  let color = undefinedColor;
191
- let drawStyle = DrawStyle.classic;
186
+ let drawStyle = bio.DrawStyle.classic;
192
187
  if (gridCell.cell.column.getTag('aligned').includes('MSA') && gridCell.cell.column.getTag('units') === 'separator')
193
- drawStyle = DrawStyle.MSA;
188
+ drawStyle = bio.DrawStyle.MSA;
194
189
 
195
190
  subParts.every((amino, index) => {
196
191
  color = palette.get(amino);
197
192
  g.fillStyle = undefinedColor;
198
193
  let last = index === subParts.length - 1;
199
- x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell, referenceSequence, maxLengthOfMonomer);
194
+ x1 = bio.printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell, referenceSequence, maxLengthOfMonomer);
200
195
  return x1 - minDistanceRenderer - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x) <= gridCell.bounds.width;
201
196
  });
202
197
 
@@ -233,7 +228,9 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
233
228
  g.textAlign = 'center';
234
229
 
235
230
  const palette = getPaletteByType(gridCell.cell.column.getTag(C.TAGS.ALPHABET));
236
- const s: string = gridCell.cell.value || '-';
231
+ const s: string = gridCell.cell.value;
232
+ if (!s)
233
+ return;
237
234
  const color = palette.get(s);
238
235
 
239
236
  g.fillStyle = color;
@@ -273,10 +270,10 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
273
270
  w = getUpdatedWidth(grid, g, x, w);
274
271
  //TODO: can this be replaced/merged with splitSequence?
275
272
  const [s1, s2] = s.split('#');
276
- const splitter = WebLogo.getSplitter(units, separator);
273
+ const splitter = bio.getSplitter(units, separator);
277
274
  const subParts1 = splitter(s1);
278
275
  const subParts2 = splitter(s2);
279
- drawMoleculeDifferenceOnCanvas(g, x, y, w, h, subParts1, subParts2, units, separator);
276
+ drawMoleculeDifferenceOnCanvas(g, x, y, w, h, subParts1, subParts2, units);
280
277
  }
281
278
  }
282
279
 
@@ -315,7 +312,7 @@ export function drawMoleculeDifferenceOnCanvas(
315
312
  g.font = '12px monospace';
316
313
  g.textBaseline = 'top';
317
314
 
318
- let palette: SeqPalette = UnknownSeqPalettes.Color;
315
+ let palette: bio.SeqPalette = bio.UnknownSeqPalettes.Color;
319
316
  if (units != 'HELM')
320
317
  palette = getPaletteByType(units.substring(units.length - 2));
321
318
 
@@ -327,12 +324,12 @@ export function drawMoleculeDifferenceOnCanvas(
327
324
 
328
325
  if (amino1 != amino2) {
329
326
  const color2 = palette.get(amino2);
330
- const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
331
- const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
327
+ const subX0 = bio.printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
328
+ const subX1 = bio.printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
332
329
  updatedX = Math.max(subX1, subX0);
333
330
  if (molDifferences)
334
331
  molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
335
- } else { updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5); }
332
+ } else { updatedX = bio.printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5); }
336
333
  updatedX += 4;
337
334
  }
338
335
  g.restore();
@@ -356,7 +353,7 @@ function createDifferenceCanvas(
356
353
  canvas.width = width + 4;
357
354
  context.font = '12px monospace';
358
355
  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);
356
+ bio.printLeftOrCentered(0, y - shift, width, h, context, amino1, color1, 0, true);
357
+ bio.printLeftOrCentered(0, y + shift, width, h, context, amino2, color2, 0, true);
361
358
  return canvas;
362
359
  }
@@ -1,11 +1,10 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as grok from 'datagrok-api/grok';
4
+ import * as bio from '@datagrok-libraries/bio';
4
5
 
5
6
  import $ from 'cash-dom';
6
7
  import {Subscription} from 'rxjs';
7
- import {NotationConverter} from '@datagrok-libraries/bio/src/utils/notation-converter';
8
- import {NOTATION, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
9
8
 
10
9
 
11
10
  let convertDialog: DG.Dialog | null = null;
@@ -17,13 +16,13 @@ let convertDialogSubs: Subscription[] = [];
17
16
  * @param {DG.column} col Column with 'Macromolecule' semantic type
18
17
  */
19
18
  export function convert(col: DG.Column): void {
20
- const converter = new NotationConverter(col);
21
- const currentNotation: NOTATION = converter.notation;
19
+ const converter = new bio.NotationConverter(col);
20
+ const currentNotation: bio.NOTATION = converter.notation;
22
21
  //TODO: read all notations
23
22
  const notations = [
24
- NOTATION.FASTA,
25
- NOTATION.SEPARATOR,
26
- NOTATION.HELM
23
+ bio.NOTATION.FASTA,
24
+ bio.NOTATION.SEPARATOR,
25
+ bio.NOTATION.HELM
27
26
  ];
28
27
  const separatorArray = ['-', '.', '/'];
29
28
  const filteredNotations = notations.filter((e) => e !== currentNotation);
@@ -33,7 +32,7 @@ export function convert(col: DG.Column): void {
33
32
 
34
33
  // hide the separator input for non-SEPARATOR target notations
35
34
  const toggleSeparator = () => {
36
- if (targetNotationInput.value !== NOTATION.SEPARATOR)
35
+ if (targetNotationInput.value !== bio.NOTATION.SEPARATOR)
37
36
  $(separatorInput.root).hide();
38
37
  else
39
38
  $(separatorInput.root).show();
@@ -64,7 +63,7 @@ export function convert(col: DG.Column): void {
64
63
  separatorInput.root
65
64
  ]))
66
65
  .onOK(async () => {
67
- const targetNotation = targetNotationInput.value as NOTATION;
66
+ const targetNotation = targetNotationInput.value as bio.NOTATION;
68
67
  const separator: string | null = separatorInput.value;
69
68
 
70
69
  await convertDo(col, targetNotation, separator);
@@ -81,9 +80,9 @@ export function convert(col: DG.Column): void {
81
80
 
82
81
  /** Creates a new column with converted sequences and detects its semantic type */
83
82
  export async function convertDo(
84
- srcCol: DG.Column, targetNotation: NOTATION, separator: string | null
83
+ srcCol: DG.Column, targetNotation: bio.NOTATION, separator: string | null
85
84
  ): Promise<DG.Column> {
86
- const converter = new NotationConverter(srcCol);
85
+ const converter = new bio.NotationConverter(srcCol);
87
86
  const newColumn = converter.convert(targetNotation, separator);
88
87
  srcCol.dataFrame.columns.add(newColumn);
89
88
 
@@ -1,9 +1,9 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as grok from 'datagrok-api/grok';
4
- import {SplitterFunc, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
4
+ import * as bio from '@datagrok-libraries/bio';
5
+
5
6
  import wu from 'wu';
6
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
7
7
 
8
8
  const FASTA_LINE_WIDTH = 60;
9
9
 
@@ -27,7 +27,7 @@ export function saveAsFastaUI() {
27
27
  .filter((gc: DG.GridColumn) => {
28
28
  const col: DG.Column | null = gc.column;
29
29
  if (col && col.semType === DG.SEMTYPE.MACROMOLECULE) {
30
- const uh = new UnitsHandler(col);
30
+ const uh = new bio.UnitsHandler(col);
31
31
  return uh.isFasta();
32
32
  }
33
33
  return false;
@@ -69,7 +69,7 @@ export function saveAsFastaUI() {
69
69
  export function saveAsFastaDo(
70
70
  idColList: DG.Column[], seqCol: DG.Column, lineWidth: number = FASTA_LINE_WIDTH, lineSeparator: string = '\n'
71
71
  ): string {
72
- const splitter: SplitterFunc = WebLogo.splitterAsFasta;
72
+ const splitter: bio.SplitterFunc = bio.splitterAsFasta;
73
73
 
74
74
  const fastaLines: string[] = [];
75
75
 
@@ -91,7 +91,7 @@ export function saveAsFastaDo(
91
91
  }
92
92
 
93
93
  /* split sequence for monomers to prevent wrapping monomer partially */
94
- export function wrapSequence(seq: string, splitter: SplitterFunc, lineWidth: number = FASTA_LINE_WIDTH): string[] {
94
+ export function wrapSequence(seq: string, splitter: bio.SplitterFunc, lineWidth: number = FASTA_LINE_WIDTH): string[] {
95
95
  const seqMonomerList = splitter(seq);
96
96
  let seqPos: number = 0;
97
97
  const seqLength: number = seqMonomerList.length;
@@ -1,6 +1,8 @@
1
- import * as DG from 'datagrok-api/dg';
2
- import {WebLogo, SplitterFunc} from '@datagrok-libraries/bio/src/viewers/web-logo';
3
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 bio from '@datagrok-libraries/bio';
5
+
4
6
  import {
5
7
  CAP_GROUP_NAME, CAP_GROUP_SMILES, jsonSdfMonomerLibDict, MONOMER_ENCODE_MAX, MONOMER_ENCODE_MIN, MONOMER_SYMBOL,
6
8
  RGROUP_ALTER_ID, RGROUP_FIELD, RGROUP_LABEL, SDF_MONOMER_NAME
@@ -18,7 +20,7 @@ export function encodeMonomers(col: DG.Column): DG.Column | null {
18
20
  const monomerSymbolDict: { [key: string]: number } = {};
19
21
  const units = col.tags[DG.TAGS.UNITS];
20
22
  const sep = col.getTag(UnitsHandler.TAGS.separator);
21
- const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, sep);
23
+ const splitterFunc: bio.SplitterFunc = bio.getSplitter(units, sep);
22
24
  const encodedStringArray = [];
23
25
  for (let i = 0; i < col.length; ++i) {
24
26
  let encodedMonomerStr = '';
@@ -42,7 +44,7 @@ export function encodeMonomers(col: DG.Column): DG.Column | null {
42
44
  export function getMolfilesFromSeq(col: DG.Column, monomersLibObject: any[]): any[][] | null {
43
45
  const units = col.tags[DG.TAGS.UNITS];
44
46
  const sep = col.getTag('separator');
45
- const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, sep);
47
+ const splitterFunc: bio.SplitterFunc = bio.getSplitter(units, sep);
46
48
  const monomersDict = createMomomersMolDict(monomersLibObject);
47
49
  const molFiles = [];
48
50
  for (let i = 0; i < col.length; ++i) {
@@ -66,7 +68,7 @@ export function getMolfilesFromSeq(col: DG.Column, monomersLibObject: any[]): an
66
68
  export function getMolfilesFromSingleSeq(cell: DG.Cell, monomersLibObject: any[]): any[][] | null {
67
69
  const units = cell.column.tags[DG.TAGS.UNITS];
68
70
  const sep = cell.column!.getTag('separator');
69
- const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, sep);
71
+ const splitterFunc: bio.SplitterFunc = bio.getSplitter(units, sep);
70
72
  const monomersDict = createMomomersMolDict(monomersLibObject);
71
73
  const molFiles = [];
72
74
  const macroMolecule = cell.value;
@@ -1,12 +1,9 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as DG from 'datagrok-api/dg';
4
+ import * as bio from '@datagrok-libraries/bio';
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';
7
- import {WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
8
-
9
- const vrt = VdRegionType;
6
+ const vrt = bio.VdRegionType;
10
7
 
11
8
  // Positions of regions for numbering schemes
12
9
  // http://www.bioinf.org.uk/abs/info.html
@@ -37,7 +34,7 @@ const vrt = VdRegionType;
37
34
  /** Viewer with tabs based on description of chain regions.
38
35
  * Used to define regions of an immunoglobulin LC.
39
36
  */
40
- export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
37
+ export class VdRegionsViewer extends DG.JsViewer implements bio.IVdRegionsViewer {
41
38
  // private regionsDf: DG.DataFrame;
42
39
  private regionsFg: DG.FilterGroup | null = null;
43
40
  // private regionsTV: DG.TableView;
@@ -46,7 +43,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
46
43
  private isOpened: boolean = false;
47
44
  private panelNode: DG.DockNode | null = null;
48
45
 
49
- public regions: VdRegion[] = [];
46
+ public regions: bio.VdRegion[] = [];
50
47
  public regionTypes: string[];
51
48
  public chains: string[];
52
49
  public sequenceColumnNamePostfix: string;
@@ -60,7 +57,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
60
57
  }
61
58
 
62
59
  // TODO: .onTableAttached is not calling on dataFrame set, onPropertyChanged also not calling
63
- public async setDf(value: DG.DataFrame, regions: VdRegion[]) {
60
+ public async setDf(value: DG.DataFrame, regions: bio.VdRegion[]) {
64
61
  console.debug('VdRegionsViewer.setDf()');
65
62
  await this.destroyView();
66
63
  this.regions = regions;
@@ -177,7 +174,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
177
174
  //#region -- View --
178
175
  private host: HTMLElement | null = null;
179
176
  private mainLayout: HTMLTableElement | null = null;
180
- private logos: { [chain: string]: WebLogo }[] = [];
177
+ private logos: { [chain: string]: bio.WebLogo }[] = [];
181
178
 
182
179
  private async destroyView(): Promise<void> {
183
180
  // TODO: Unsubscribe from and remove all view elements
@@ -197,16 +194,16 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
197
194
  const colNames: { [chain: string]: string } = Object.assign({},
198
195
  ...this.chains.map((chain) => ({[chain]: `${chain} ${this.sequenceColumnNamePostfix}`})));
199
196
 
200
- const regionsFiltered: VdRegion[] = this.regions.filter((r: VdRegion) => this.regionTypes.includes(r.type));
197
+ const regionsFiltered: bio.VdRegion[] = this.regions.filter((r: bio.VdRegion) => this.regionTypes.includes(r.type));
201
198
 
202
199
  const orderList: number[] = Array.from(new Set(regionsFiltered.map((r) => r.order))).sort();
203
200
 
204
201
  this.logos = [];
205
202
 
206
203
  for (let orderI = 0; orderI < orderList.length; orderI++) {
207
- const regionChains: { [chain: string]: WebLogo } = {};
204
+ const regionChains: { [chain: string]: bio.WebLogo } = {};
208
205
  for (const chain of this.chains) {
209
- const region: VdRegion | undefined = regionsFiltered
206
+ const region: bio.VdRegion | undefined = regionsFiltered
210
207
  .find((r) => r.order == orderList[orderI] && r.chain == chain);
211
208
  regionChains[chain] = (await this.dataFrame.plot.fromType('WebLogo', {
212
209
  sequenceColumnName: colNames[chain],
@@ -215,7 +212,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
215
212
  fixWidth: true,
216
213
  skipEmptyPositions: this.skipEmptyPositions,
217
214
  positionWidth: this.positionWidth,
218
- })) as unknown as WebLogo;
215
+ })) as unknown as bio.WebLogo;
219
216
  }
220
217
  // WebLogo creation fires onRootSizeChanged event even before control being added to this.logos
221
218
  this.logos[orderI] = regionChains;
@@ -240,7 +237,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
240
237
  })] : []),
241
238
  // List with controls for regions
242
239
  ...[...Array(orderList.length).keys()].map((orderI) => {
243
- const wl: WebLogo = this.logos[orderI][chain];
240
+ const wl: bio.WebLogo = this.logos[orderI][chain];
244
241
  wl.root.style.height = '100%';
245
242
 
246
243
  const resDiv = ui.div([wl.root]/*`${chain} ${regionsFiltered[rI]}`*/, {
@@ -257,7 +254,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
257
254
  },
258
255
  ['', ...[...Array(orderList.length).keys()].map(
259
256
  (orderI: number) => regionsFiltered.find(
260
- (r: VdRegion) => r.order == orderList[orderI] && r.chain == this.chains[0]
257
+ (r: bio.VdRegion) => r.order == orderList[orderI] && r.chain == this.chains[0]
261
258
  )!.name || 'Name')]
262
259
  );
263
260
  this.mainLayout.className = 'mlb-vd-regions-viewer-table2';
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Macromolecules substructure filter that uses Datagrok's collaborative filtering.
3
+ * 1. On onRowsFiltering event, only FILTER OUT rows that do not satisfy this filter's criteria
4
+ * 2. Call dataFrame.rows.requestFilter when filtering criteria changes.
5
+ * */
6
+
7
+ import * as ui from 'datagrok-api/ui';
8
+ import * as DG from 'datagrok-api/dg';
9
+ import wu from 'wu';
10
+ import {linearSubstructureSearch} from '../substructure-search/substructure-search';
11
+ import {Subject, Subscription} from 'rxjs';
12
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/units-handler';
13
+ import * as C from '../utils/constants';
14
+
15
+ export class BioSubstructureFilter extends DG.Filter {
16
+ bioFilter: FastaFilter | SeparatorFilter | null = null;
17
+ bitset: DG.BitSet | null = null;
18
+ loader: HTMLDivElement = ui.loader();
19
+ onBioFilterChangedSubs?: Subscription;
20
+
21
+ get calculating(): boolean { return this.loader.style.display == 'initial'; }
22
+ set calculating(value: boolean) { this.loader.style.display = value ? 'initial' : 'none'; }
23
+
24
+ get filterSummary(): string {
25
+ return this.bioFilter!.substructure;
26
+ }
27
+
28
+ get isFiltering(): boolean {
29
+ return super.isFiltering && this.bioFilter!.substructure !== '';
30
+ }
31
+
32
+ get isReadyToApplyFilter(): boolean {
33
+ return !this.calculating && this.bitset != null;
34
+ }
35
+
36
+ constructor() {
37
+ super();
38
+ this.root = ui.divV([]);
39
+ this.calculating = false;
40
+ }
41
+
42
+ attach(dataFrame: DG.DataFrame): void {
43
+ super.attach(dataFrame);
44
+ this.column = dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
45
+ this.columnName = this.column?.name;
46
+ const notation = this.column?.getTag(DG.TAGS.UNITS);
47
+ this.bioFilter = notation === NOTATION.FASTA ?
48
+ new FastaFilter() : new SeparatorFilter(this.column!.getTag(C.TAGS.SEPARATOR));
49
+ this.root.appendChild(this.bioFilter!.filterPanel);
50
+ this.root.appendChild(this.loader);
51
+
52
+ this.onBioFilterChangedSubs?.unsubscribe();
53
+ const onChangedEvent: any = this.bioFilter.onChanged;
54
+ this.onBioFilterChangedSubs = onChangedEvent.subscribe(async (_: any) => await this._onInputChanged());
55
+ }
56
+
57
+ detach() {
58
+ super.detach();
59
+ }
60
+
61
+ applyFilter(): void {
62
+ if (this.bitset && !this.isDetached)
63
+ this.dataFrame?.filter.and(this.bitset);
64
+ }
65
+
66
+ /** Override to save filter state. */
67
+ saveState(): any {
68
+ const state = super.saveState();
69
+ state.bioSubstructure = this.bioFilter?.substructure;
70
+ return state;
71
+ }
72
+
73
+ /** Override to load filter state. */
74
+ applyState(state: any): void {
75
+ super.applyState(state);
76
+ if (state.bioSubstructure)
77
+ this.bioFilter!.substructureInput.value = state.bioSubstructure;
78
+
79
+ const that = this;
80
+ if (state.bioSubstructure)
81
+ setTimeout(function() { that._onInputChanged(); }, 1000);
82
+ }
83
+
84
+ /**
85
+ * Performs the actual filtering
86
+ * When the results are ready, triggers `rows.requestFilter`, which in turn triggers `applyFilter`
87
+ * that would simply apply the bitset synchronously.
88
+ */
89
+ async _onInputChanged(): Promise<void> {
90
+ if (!this.isFiltering) {
91
+ this.bitset = null;
92
+ this.dataFrame?.rows.requestFilter();
93
+ } else if (wu(this.dataFrame!.rows.filters).has(`${this.columnName}: ${this.filterSummary}`)) {
94
+ // some other filter is already filtering for the exact same thing
95
+ return;
96
+ } else {
97
+ this.calculating = true;
98
+ try {
99
+ this.bitset = linearSubstructureSearch(this.bioFilter!.substructure, this.column!);
100
+ this.calculating = false;
101
+ this.dataFrame?.rows.requestFilter();
102
+ } finally {
103
+ this.calculating = false;
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ class FastaFilter {
110
+ onChanged: Subject<any> = new Subject<any>();
111
+ substructureInput: DG.InputBase<string> = ui.stringInput('', '', () => {
112
+ this.onChanged.next();
113
+ }, {placeholder: 'Substructure'});
114
+
115
+ constructor() {
116
+ }
117
+
118
+ get filterPanel() {
119
+ return this.substructureInput.root;
120
+ }
121
+
122
+ get substructure() {
123
+ return this.substructureInput.value;
124
+ }
125
+ }
126
+
127
+ class SeparatorFilter extends FastaFilter {
128
+ separatorInput: DG.InputBase<string> = ui.stringInput('', '', () => {
129
+ this.onChanged.next();
130
+ }, {placeholder: 'Separator'});
131
+ colSeparator = '';
132
+
133
+ constructor(separator: string) {
134
+ super();
135
+ this.colSeparator = separator;
136
+ this.separatorInput.value = separator;
137
+ }
138
+
139
+ get filterPanel() {
140
+ return ui.divV([
141
+ this.substructureInput.root,
142
+ this.separatorInput.root
143
+ ]);
144
+ }
145
+
146
+ get substructure() {
147
+ return this.separatorInput.value && this.separatorInput.value !== this.colSeparator ?
148
+ this.substructureInput.value.replaceAll(this.separatorInput.value, this.colSeparator):
149
+ this.substructureInput.value;
150
+ }
151
+ }