@datagrok/bio 2.10.4 → 2.10.6

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/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@datagrok/bio",
3
3
  "friendlyName": "Bio",
4
- "skipCI": true,
5
4
  "author": {
6
5
  "name": "Leonid Stolbov",
7
6
  "email": "lstolbov@datagrok.ai"
8
7
  },
9
- "version": "2.10.4",
8
+ "version": "2.10.6",
10
9
  "description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
11
10
  "repository": {
12
11
  "type": "git",
@@ -35,7 +34,7 @@
35
34
  ],
36
35
  "dependencies": {
37
36
  "@biowasm/aioli": "^3.1.0",
38
- "@datagrok-libraries/bio": "^5.38.3",
37
+ "@datagrok-libraries/bio": "^5.38.4",
39
38
  "@datagrok-libraries/chem-meta": "^1.0.1",
40
39
  "@datagrok-libraries/ml": "^6.3.39",
41
40
  "@datagrok-libraries/tutorials": "^1.3.6",
@@ -64,7 +63,7 @@
64
63
  "webpack-bundle-analyzer": "latest",
65
64
  "webpack-cli": "^4.9.1",
66
65
  "@datagrok/chem": "1.7.2",
67
- "@datagrok/helm": "2.1.16"
66
+ "@datagrok/helm": "2.1.17"
68
67
  },
69
68
  "scripts": {
70
69
  "link-api": "npm link datagrok-api",
@@ -22,7 +22,7 @@ export class SequenceDiversityViewer extends SequenceSearchBaseViewer {
22
22
  this.diverseColumnLabel = this.string('diverseColumnLabel', null);
23
23
  }
24
24
 
25
- async render(computeData = true): Promise<void> {
25
+ override async renderInt(computeData: boolean): Promise<void> {
26
26
  if (!this.beforeRender())
27
27
  return;
28
28
  if (this.dataFrame) {
@@ -6,6 +6,7 @@ import {CHEM_SIMILARITY_METRICS} from '@datagrok-libraries/ml/src/distance-metri
6
6
  import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
7
 
8
8
  const MAX_ROWS_FOR_DISTANCE_MATRIX = 22000;
9
+
9
10
  export class SequenceSearchBaseViewer extends DG.JsViewer {
10
11
  name: string = '';
11
12
  distanceMetric: string;
@@ -13,11 +14,12 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
13
14
  fingerprint: string;
14
15
  metricsProperties = ['distanceMetric', 'fingerprint'];
15
16
  fingerprintChoices = ['Morgan', 'Pattern'];
16
- moleculeColumn?: DG.Column|null;
17
+ moleculeColumn?: DG.Column | null;
17
18
  moleculeColumnName: string;
18
19
  initialized: boolean = false;
19
20
  tags = [DG.TAGS.UNITS, bioTAGS.aligned, bioTAGS.separator, bioTAGS.alphabet];
20
21
  preComputeDistanceMatrix: boolean = false;
22
+
21
23
  constructor(name: string) {
22
24
  super();
23
25
  this.fingerprint = this.string('fingerprint', this.fingerprintChoices[0], {choices: this.fingerprintChoices});
@@ -40,19 +42,20 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
40
42
 
41
43
  if (this.dataFrame) {
42
44
  this.preComputeDistanceMatrix = this.dataFrame.rowCount <= MAX_ROWS_FOR_DISTANCE_MATRIX;
43
- this.subs.push(DG.debounce(this.dataFrame.onRowsRemoved, 50).subscribe(async (_: any) => await this.render()));
45
+ this.subs.push(DG.debounce(this.dataFrame.onRowsRemoved, 50)
46
+ .subscribe((_: any) => this.render(true)));
44
47
  const compute = this.name !== 'diversity';
45
48
  this.subs.push(DG.debounce(this.dataFrame.onCurrentRowChanged, 50)
46
- .subscribe(async (_: any) => await this.render(compute)));
49
+ .subscribe((_: any) => this.render(compute)));
47
50
  this.subs.push(DG.debounce(this.dataFrame.selection.onChanged, 50)
48
- .subscribe(async (_: any) => await this.render(false)));
51
+ .subscribe((_: any) => this.render(false)));
49
52
  this.subs.push(DG.debounce(ui.onSizeChanged(this.root), 50)
50
- .subscribe(async (_: any) => await this.render(false)));
53
+ .subscribe((_: any) => this.render(false)));
51
54
  this.moleculeColumn = this.dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
52
55
  this.moleculeColumnName = this.moleculeColumn?.name!;
53
56
  this.getProperty('limit')!.fromOptions({min: 1, max: this.dataFrame.rowCount});
54
57
  }
55
- await this.render();
58
+ this.render();
56
59
  }
57
60
 
58
61
  onPropertyChanged(property: DG.Property): void {
@@ -67,7 +70,17 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
67
70
  this.render();
68
71
  }
69
72
 
70
- async render(_computeData = true) {
73
+ /** For tests */ public computeRequested: boolean;
74
+ public renderPromise: Promise<void> = Promise.resolve();
75
+
76
+ protected render(computeData = true): void {
77
+ this.renderPromise = this.renderPromise.then(async () => {
78
+ this.computeRequested = this.computeRequested || computeData;
79
+ await this.renderInt(computeData);
80
+ });
81
+ }
82
+
83
+ async renderInt(_computeData: boolean): Promise<void> {
71
84
 
72
85
  }
73
86
 
@@ -39,7 +39,7 @@ export class SequenceSimilarityViewer extends SequenceSearchBaseViewer {
39
39
  this.initialized = true;
40
40
  }
41
41
 
42
- async render(computeData = true): Promise<void> {
42
+ override async renderInt(computeData: boolean): Promise<void> {
43
43
  if (!this.beforeRender())
44
44
  return;
45
45
  if (this.moleculeColumn) {
package/src/package.ts CHANGED
@@ -162,13 +162,6 @@ export function getBioLib(): IMonomerLib {
162
162
  //input: column seqCol {semType: Macromolecule}
163
163
  //output: widget result
164
164
  export function getRegionPanel(seqCol: DG.Column<string>): DG.Widget {
165
- // const host = ui.divV([
166
- // ui.inputs([
167
- // ui.stringInput('Region', ''),
168
- // ]),
169
- // ui.button('Ok', () => {})
170
- // ]);
171
- // return DG.Widget.fromRoot(host);
172
165
  const funcName: string = 'getRegionTopMenu';
173
166
  const funcList = DG.Func.find({package: _package.name, name: funcName});
174
167
  if (funcList.length !== 1) throw new Error(`Package '${_package.name}' func '${funcName}' not found`);
@@ -357,7 +350,7 @@ export function getRegion(
357
350
  }
358
351
 
359
352
  //top-menu: Bio | Convert | Get Region...
360
- //name: Get Region
353
+ //name: Get Region Top Menu
361
354
  //description: Get sequences for a region specified from a Macromolecule
362
355
  //input: dataframe table [Input data table]
363
356
  //input: column sequence {semType: Macromolecule} [Sequence column]
@@ -784,7 +777,7 @@ export function similaritySearchViewer(): SequenceSimilarityViewer {
784
777
  return new SequenceSimilarityViewer();
785
778
  }
786
779
 
787
- //top-menu: Bio | Search | Similarity
780
+ //top-menu: Bio | Search | Similarity Search
788
781
  //name: similaritySearch
789
782
  //description: Finds similar sequences
790
783
  //output: viewer result
@@ -802,7 +795,7 @@ export function diversitySearchViewer(): SequenceDiversityViewer {
802
795
  return new SequenceDiversityViewer();
803
796
  }
804
797
 
805
- //top-menu: Bio | Search | Diversity
798
+ //top-menu: Bio | Search | Diversity Search
806
799
  //name: diversitySearch
807
800
  //description: Finds the most diverse sequences
808
801
  //output: viewer result
@@ -823,7 +816,7 @@ export function searchSubsequenceEditor(call: DG.FuncCall) {
823
816
  new SubstructureSearchDialog(columns);
824
817
  }
825
818
 
826
- //top-menu: Bio | Search | Subsequence...
819
+ //top-menu: Bio | Search | Subsequence Search ...
827
820
  //name: Subsequence Search
828
821
  //input: column macromolecules
829
822
  //editor: Bio:SearchSubsequenceEditor
@@ -38,7 +38,7 @@ category('activityCliffs', async () => {
38
38
  const cliffsNum = DG.Test.isInBenchmark ? 6 : 3;
39
39
 
40
40
  await _testActivityCliffsOpen(actCliffsDf, cliffsNum, DimReductionMethods.UMAP, 'sequence');
41
- });
41
+ }, {skipReason: 'GROK-13952'});
42
42
 
43
43
  test('activityCliffsWithEmptyRows', async () => {
44
44
  actCliffsDfWithEmptyRows = await readDataframe('tests/100_3_clustests_empty_vals.csv');
@@ -1,8 +1,9 @@
1
- import {category, test, expect, awaitCheck} from '@datagrok-libraries/utils/src/test';
1
+ import {category, test, expect, awaitCheck, delay} from '@datagrok-libraries/utils/src/test';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import {createTableView} from './utils';
4
4
  import * as grok from 'datagrok-api/grok';
5
5
  import {SequenceSimilarityViewer} from '../analysis/sequence-similarity-viewer';
6
+ import {SequenceDiversityViewer} from '../analysis/sequence-diversity-viewer';
6
7
 
7
8
  category('similarity/diversity', async () => {
8
9
  test('similaritySearchViewer', async () => {
@@ -15,49 +16,86 @@ category('similarity/diversity', async () => {
15
16
  });
16
17
 
17
18
  async function _testSimilaritySearchViewer() {
18
- const molecules = await createTableView('tests/sample_MSA_data.csv');
19
- const viewer = molecules.addViewer('Sequence Similarity Search');
20
- await awaitCheck(() => getSearchViewer(viewer, 'Sequence Similarity Search') !== undefined,
21
- 'Sequence Similarity Search has not been created', 5000);
22
- const similaritySearchViewer: SequenceSimilarityViewer = getSearchViewer(viewer, 'Sequence Similarity Search');
19
+ const moleculesView = await createTableView('tests/sample_MSA_data.csv');
20
+
21
+ const viewer: SequenceSimilarityViewer = (await moleculesView.dataFrame.plot
22
+ .fromType('Sequence Similarity Search')) as SequenceSimilarityViewer;
23
+ let computeCompleted: boolean = false;
24
+ viewer.computeCompleted.subscribe((value) => {
25
+ if (value) computeCompleted = true;
26
+ });
27
+ moleculesView.dockManager.dock(viewer, DG.DOCK_TYPE.RIGHT, null, 'Similarity');
28
+ await viewer.renderPromise; // required to wait for computeCompleted
29
+
30
+ await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Similarity Search') !== undefined,
31
+ 'Sequence Similarity Search viewer has not been created', 100);
32
+ if (!viewer.initialized) throw new Error('The viewer is not initialized.');
33
+ if (!viewer.moleculeColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
34
+ if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
35
+ if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
36
+ if (!computeCompleted) throw new Error('The viewer has not compute completed.');
37
+
38
+ const similaritySearchViewer = viewer;
23
39
  await awaitCheck(() => similaritySearchViewer.root.getElementsByClassName('d4-grid').length !== 0,
24
- 'Sequence Similarity Search has not been created', 5000);
40
+ 'Sequence Similarity Search viewer grid has not been created', 100);
41
+
42
+ /* eslint-disable max-len */
43
+ const str0: string = 'D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me';
44
+ const str1: string = 'meI/hHis//Aca/meM/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me';
45
+ const simStr1: string = 'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Phe_ab-dehydro/N/D-Orn/D-aThr//Phe_4Me';
46
+ /* eslint-enable max-len */
47
+
25
48
  expect(similaritySearchViewer.fingerprint, 'Morgan');
26
49
  expect(similaritySearchViewer.distanceMetric, 'Tanimoto');
27
50
  expect(similaritySearchViewer.scores!.get(0), DG.FLOAT_NULL);
28
51
  expect(similaritySearchViewer.idxs!.get(0), 0);
29
- expect(similaritySearchViewer.molCol!.get(0),
30
- 'D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me');
52
+ expect(similaritySearchViewer.molCol!.get(0), str0);
31
53
  expect(similaritySearchViewer.scores!.get(1), 0.4722222089767456);
32
54
  expect(similaritySearchViewer.idxs!.get(1), 11);
33
- expect(similaritySearchViewer.molCol!.get(1),
34
- 'meI/hHis//Aca/meM/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me');
35
- molecules.dataFrame.currentRowIdx = 1;
55
+ expect(similaritySearchViewer.molCol!.get(1), str1);
56
+ moleculesView.dataFrame.currentRowIdx = 1;
36
57
  await awaitCheck(() => similaritySearchViewer.targetMoleculeIdx === 1,
37
58
  'Target molecule has not been changed', 5000);
38
- await awaitCheck(() => similaritySearchViewer.molCol!.get(0) ===
39
- 'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Phe_ab-dehydro/N/D-Orn/D-aThr//Phe_4Me',
40
- 'Incorrect first similar molecule', 5000);
59
+ await awaitCheck(() => similaritySearchViewer.molCol!.get(0) === simStr1,
60
+ 'Incorrect first similar molecule', 5000);
41
61
  }
42
62
 
43
63
  async function _testDiversitySearchViewer() {
44
- const molecules = await createTableView('tests/sample_MSA_data.csv');
45
- const viewer = molecules.addViewer('Sequence Diversity Search');
46
- await awaitCheck(() => getSearchViewer(viewer, 'Sequence Diversity Search') !== undefined,
47
- 'Sequence Diversity Search has not been created', 5000);
48
- const diversitySearchviewer = getSearchViewer(viewer, 'Sequence Diversity Search');
49
- await awaitCheck(() => diversitySearchviewer.root.getElementsByClassName('d4-grid').length !== 0,
50
- 'Sequence Diversity Search has not been created', 5000);
51
- expect(diversitySearchviewer.fingerprint, 'Morgan');
52
- expect(diversitySearchviewer.distanceMetric, 'Tanimoto');
53
- expect(diversitySearchviewer.initialized, true);
54
- expect(diversitySearchviewer.renderMolIds.length > 0, true);
64
+ const moleculesView = await createTableView('tests/sample_MSA_data.csv');
65
+
66
+ const viewer: SequenceDiversityViewer = (await moleculesView.dataFrame.plot
67
+ .fromType('Sequence Diversity Search')) as SequenceDiversityViewer;
68
+ let computeCompleted: boolean = false;
69
+ viewer.computeCompleted.subscribe((value) => {
70
+ if (value) computeCompleted = true;
71
+ });
72
+ moleculesView.dockManager.dock(viewer, DG.DOCK_TYPE.DOWN, null, 'Diversity');
73
+ await viewer.renderPromise;
74
+
75
+ await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Diversity Search') !== undefined,
76
+ 'Sequence Diversity Search viewer has not been created', 100);
77
+ if (!viewer.initialized) throw new Error('The viewer is not initialized.');
78
+ if (!viewer.moleculeColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
79
+ if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
80
+ if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
81
+ if (!computeCompleted) throw new Error('The viewer has not compute completed.');
82
+
83
+ //const diversitySearchViewer = getSearchViewer(viewer, 'Sequence Diversity Search');
84
+ const diversitySearchViewer = viewer;
85
+ await awaitCheck(() => diversitySearchViewer.root.getElementsByClassName('d4-grid').length !== 0,
86
+ 'Sequence Diversity Search viewer grid has not been created', 100);
87
+
88
+ expect(diversitySearchViewer.fingerprint, 'Morgan');
89
+ expect(diversitySearchViewer.distanceMetric, 'Tanimoto');
90
+ expect(diversitySearchViewer.initialized, true);
91
+ expect(diversitySearchViewer.renderMolIds!.length > 0, true);
55
92
  }
56
93
 
57
- function getSearchViewer(viewer: DG.Viewer, name: string) {
58
- //@ts-ignore
59
- for (const v of viewer.view.viewers) {
94
+ function getSearchViewer(tv: DG.TableView, name: string): DG.Viewer | null {
95
+ let res: DG.Viewer | null = null;
96
+ for (const v of tv.viewers) {
60
97
  if (v.type === name)
61
- return v;
98
+ res = v;
62
99
  }
100
+ return res;
63
101
  }
@@ -12,6 +12,13 @@ category('viewers', () => {
12
12
  test(v, async () => {
13
13
  const df = await readDataframe('data/sample_FASTA_DNA.csv');
14
14
  await testViewer(v, df, {detectSemanticTypes: true});
15
- }, v === 'Sequence Similarity Search' ? {skipReason: 'GROK-13162'} : undefined);
15
+ }, {
16
+ skipReason: {
17
+ 'Sequence Similarity Search': 'GROK-13162',
18
+ 'Sequence Diversity Search': 'GROK-13162',
19
+ 'WebLogo': 'GROK-13162',
20
+ 'VdRegions': 'GROK-13162',
21
+ }[v],
22
+ });
16
23
  }
17
24
  });
@@ -18,7 +18,6 @@ export const rendererSettingsChangedState = {
18
18
 
19
19
  export const enum Temps {
20
20
  monomerWidth = '.mm.cellRenderer.monomerWidth',
21
- maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
22
21
  colorCode = '.mm.cellRenderer.colorCode',
23
22
  compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
24
23
  highlightDifference = '.mm.cellRenderer.highlightDifference',
@@ -4,7 +4,7 @@ import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import wu from 'wu';
6
6
 
7
- import {printLeftOrCentered, DrawStyle} from '@datagrok-libraries/bio/src/utils/cell-renderer';
7
+ import {printLeftOrCentered, DrawStyle, TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
8
8
  import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
9
9
  import {
10
10
  getPaletteByType,
@@ -132,7 +132,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
132
132
  ): void {
133
133
  let gapLength = 0;
134
134
  const msaGapLength = 8;
135
- let maxLengthOfMonomer = 999; // in case of long monomer representation, do not limit max length
135
+ let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
136
136
 
137
137
  // TODO: Store temp data to GridColumn
138
138
  // Now the renderer requires data frame table Column underlying GridColumn
@@ -146,10 +146,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
146
146
  if (monomerWidth === 'short') {
147
147
  // Renderer can start to work before Bio package initialized, in that time _package.properties is null.
148
148
  // TODO: Render function is available but package init method is not completed
149
- maxLengthOfMonomer = tableColTemp[mmcrTemps.maxMonomerLength] ?? _package.properties?.MaxMonomerLength ?? 4;
149
+ const tagMaxMonomerLength: number = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
150
+ maxLengthOfMonomer =
151
+ (!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
150
152
  }
151
153
 
152
-
153
154
  let seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
154
155
  if (!seqColTemp) {
155
156
  seqColTemp = new MonomerPlacer(grid, tableCol,
@@ -7,6 +7,7 @@ import {fromEvent, Unsubscribable} from 'rxjs';
7
7
  import {
8
8
  IVdRegionsViewer,
9
9
  VdRegion, VdRegionType,
10
+ VdRegionsProps, VdRegionsPropsDefault,
10
11
  } from '@datagrok-libraries/bio/src/viewers/vd-regions';
11
12
  import {FilterSources, IWebLogoViewer, PositionHeight} from '@datagrok-libraries/bio/src/viewers/web-logo';
12
13
 
@@ -55,11 +56,14 @@ export enum PROPS {
55
56
  regionTypes = 'regionTypes',
56
57
  chains = 'chains',
57
58
 
58
- // -- Style --
59
+ // -- Layout --
60
+ fitWidth = 'fitWidth',
59
61
  positionWidth = 'positionWidth',
60
62
  positionHeight = 'positionHeight',
61
63
  }
62
64
 
65
+ const defaults: VdRegionsProps = VdRegionsPropsDefault;
66
+
63
67
  /** Viewer with tabs based on description of chain regions.
64
68
  * Used to define regions of an immunoglobulin LC.
65
69
  */
@@ -80,7 +84,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
80
84
  // public sequenceColumnNamePostfix: string;
81
85
 
82
86
  public skipEmptyPositions: boolean;
83
- /* A value of zero means autofit to the width. */
87
+ public fitWidth: boolean;
84
88
  public positionWidth: number;
85
89
  public positionHeight: PositionHeight;
86
90
 
@@ -88,22 +92,24 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
88
92
  super();
89
93
 
90
94
  // -- Data --
91
- this.skipEmptyPositions = this.bool(PROPS.skipEmptyPositions, false,
95
+ this.skipEmptyPositions = this.bool(PROPS.skipEmptyPositions, defaults.skipEmptyPositions,
92
96
  {category: PROPS_CATS.DATA});
93
97
 
94
98
  // To prevent ambiguous numbering scheme in MLB
95
- this.regionTypes = this.stringList(PROPS.regionTypes, [vrt.CDR], {
99
+ this.regionTypes = this.stringList(PROPS.regionTypes, defaults.regionTypes, {
96
100
  category: PROPS_CATS.DATA, choices: Object.values(vrt).filter((t) => t != vrt.Unknown)
97
101
  }) as VdRegionType[];
98
- this.chains = this.stringList(PROPS.chains, ['Heavy', 'Light'],
102
+ this.chains = this.stringList(PROPS.chains, defaults.chains,
99
103
  {category: PROPS_CATS.DATA, choices: ['Heavy', 'Light']});
100
104
 
101
105
  // -- Layout --
102
- this.positionWidth = this.float(PROPS.positionWidth, 16, {
106
+ this.fitWidth = this.bool(PROPS.fitWidth, defaults.fitWidth,
107
+ {category: PROPS_CATS.LAYOUT});
108
+ this.positionWidth = this.float(PROPS.positionWidth, defaults.positionWidth, {
103
109
  category: PROPS_CATS.LAYOUT, editor: 'slider', min: 0, max: 64,
104
- description: 'Internal WebLogo viewers property width of position. A value of zero means autofit to the width.'
110
+ description: 'Internal WebLogo viewers property width of position.'
105
111
  });
106
- this.positionHeight = this.string(PROPS.positionHeight, PositionHeight.Entropy,
112
+ this.positionHeight = this.string(PROPS.positionHeight, defaults.positionHeight,
107
113
  {category: PROPS_CATS.LAYOUT, choices: Object.keys(PositionHeight)}) as PositionHeight;
108
114
  }
109
115
 
@@ -178,6 +184,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
178
184
  this.calcSize();
179
185
  break;
180
186
 
187
+ case PROPS.fitWidth:
181
188
  case PROPS.positionWidth:
182
189
  this.calcSize();
183
190
  break;
@@ -274,7 +281,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
274
281
  for (const chain of this.chains) {
275
282
  const region: VdRegion | undefined = regionsFiltered
276
283
  .find((r) => r.order == orderList[orderI] && r.chain == chain);
277
- logoPromiseList.push((async () => {
284
+ logoPromiseList.push((async (): Promise<[number, string, WebLogoViewer]> => {
278
285
  const wl: WebLogoViewer = await this.dataFrame.plot.fromType('WebLogo', {
279
286
  sequenceColumnName: region!.sequenceColumnName,
280
287
  startPositionName: region!.positionStartName,
@@ -381,7 +388,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
381
388
  totalPos += Math.max(...this.chains.map((chain) => this.logos[orderI][chain].Length));
382
389
  }
383
390
 
384
- if (this.positionWidth === 0) {
391
+ if (this.fitWidth) {
385
392
  if (this.logos.length > 0 && totalPos > 0) {
386
393
  const leftPad = 22/* Chain label */;
387
394
  const rightPad = 6 + 6 + 1;
@@ -392,16 +399,18 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
392
399
  for (let orderI = 0; orderI < this.logos.length; orderI++) {
393
400
  for (const chain of this.chains) {
394
401
  const wl = this.logos[orderI][chain];
395
- wl.setOptions({[wlPROPS.positionWidth]: fitPositionWidth});
402
+ wl.setOptions({[wlPROPS.positionWidth]: (fitPositionWidth - wl.positionMarginValue)});
396
403
  wl.root.style.width = `${fitPositionWidth * wl.Length}px`;
397
404
  }
398
405
  }
399
406
  }
407
+ this.host.style.setProperty('overflow', 'hidden', 'important');
400
408
  } else {
401
409
  for (let orderI = 0; orderI < this.logos.length; orderI++) {
402
410
  for (const chain of this.chains)
403
411
  this.logos[orderI][chain].setOptions({[wlPROPS.positionWidth]: this.positionWidth});
404
412
  }
413
+ this.host.style.removeProperty('overflow');
405
414
  }
406
415
 
407
416
  if (this.positionWidth === 0)
@@ -339,7 +339,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
339
339
  return this.startPosition <= this.endPosition ? this.endPosition - this.startPosition + 1 : 0;
340
340
  }
341
341
 
342
- private get positionMarginValue(): number {
342
+ public get positionMarginValue(): number {
343
343
  if (this.positionMarginState === PositionMarginStates.AUTO && this.unitsHandler!.getAlphabetIsMultichar() === true)
344
344
  return this.positionMargin;
345
345
  else if (this.positionMarginState === PositionMarginStates.ON)
@@ -598,12 +598,11 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
598
598
  }
599
599
  }
600
600
 
601
- /** Updates {@link host}, {@link canvas}, {@link slider}.
601
+ /** Updates {@link host}, {@link canvas}, {@link slider} .min, .max.
602
602
  * Calls {@link render} with {@link WlRenderLevel.Layout}
603
603
  */
604
604
  private calcLayout(dpr: number): void {
605
605
  if (!this.host || !this.canvas || !this.slider) return;
606
- if (this.root.clientHeight === 0 || this.root.clientWidth === 0) return;
607
606
 
608
607
  this.host.classList.remove('bio-wl-fixWidth', 'bio-wl-fitArea');
609
608
  this.canvas.classList.remove('bio-wl-fixWidth', 'bio-wl-fitArea');
@@ -892,7 +891,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
892
891
  /** Renders requested repeatedly will be performed once on window.requestAnimationFrame() */
893
892
  render(recalcLevel: WlRenderLevel, reason: string): Promise<void> {
894
893
  _package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>` +
895
- `.render( recalcLevel=${recalcLevel}, reason='${reason}' )`);
894
+ `.render( recalcLevelVal=${recalcLevel}, reason='${reason}' )`);
896
895
 
897
896
  /** Calculate freqs of monomers */
898
897
  const calculateFreqsInt = (): void => {
@@ -989,6 +988,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
989
988
  /** 0 is for no position labels */
990
989
  const positionLabelsHeight = this.showPositionLabels ? POSITION_LABELS_HEIGHT : 0;
991
990
  if (recalcLevel >= WlRenderLevel.Freqs) calculateFreqsInt();
991
+ if (this.positions.length === 0) return;
992
992
  if (recalcLevel >= WlRenderLevel.Layout) calculateLayoutInt(window.devicePixelRatio, positionLabelsHeight);
993
993
 
994
994
  const length: number = this.Length;
@@ -1,9 +1,15 @@
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 {getMolfilesFromSingleSeq} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
5
- import {Tags as mmcrTags, Temps as mmcrTemps, MonomerWidthMode,
6
- tempTAGS, rendererSettingsChangedState} from '../utils/cell-renderer-consts';
6
+ import {TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
7
+
8
+ import {
9
+ Tags as mmcrTags, Temps as mmcrTemps, MonomerWidthMode,
10
+ tempTAGS, rendererSettingsChangedState
11
+ } from '../utils/cell-renderer-consts';
12
+
7
13
  import {_package} from '../package';
8
14
 
9
15
 
@@ -31,10 +37,11 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
31
37
  `In short mode, only the 'Max monomer length' characters are displayed, followed by .. if there are more`,
32
38
  );
33
39
 
40
+ const tagMaxMonomerLength: number = parseInt(col.getTag(mmcrTAGS.maxMonomerLength));
34
41
  const maxMonomerLength: DG.InputBase = ui.intInput('Max monomer length',
35
- col.temp[mmcrTemps.maxMonomerLength] ?? _package.properties.MaxMonomerLength,
42
+ !isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties.MaxMonomerLength,
36
43
  (value: number) => {
37
- col.temp[mmcrTemps.maxMonomerLength] = value;
44
+ col.setTag(mmcrTAGS.maxMonomerLength, value.toString());
38
45
  col.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.true);
39
46
  col.dataFrame.fireValuesChanged();
40
47
  });