@datagrok/peptides 0.8.8 → 0.8.9

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/src/package.ts CHANGED
@@ -17,14 +17,14 @@ import {manualAlignmentWidget} from './widgets/manual-alignment';
17
17
  import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
18
18
  import {peptideMoleculeWidget, getMolecule} from './widgets/peptide-molecule';
19
19
  import {SubstViewer} from './viewers/subst-viewer';
20
- import {runKalign} from './utils/multiple-sequence-alignment';
21
- import { SemanticValue } from 'datagrok-api/dg';
20
+ import {substTableWidget} from './widgets/subst-table';
21
+ import {msaWidget} from './widgets/multiple-sequence-alignment';
22
22
 
23
23
  export const _package = new DG.Package();
24
- let tableGrid: DG.Grid;
25
- let currentDf: DG.DataFrame;
26
- let alignedSequenceCol: DG.Column;
27
- let view: DG.TableView;
24
+ let currentGrid: DG.Grid;
25
+ let currentTable: DG.DataFrame;
26
+ let alignedSequenceColumn: DG.Column;
27
+ let currentView: DG.TableView;
28
28
 
29
29
  async function main(chosenFile: string) {
30
30
  const pi = DG.TaskBarProgressIndicator.create('Loading Peptides');
@@ -33,7 +33,7 @@ async function main(chosenFile: string) {
33
33
  peptides.name = 'Peptides';
34
34
  peptides.setTag('dataType', 'peptides');
35
35
  const view = grok.shell.addTableView(peptides);
36
- tableGrid = view.grid;
36
+ currentGrid = view.grid;
37
37
  view.name = 'PeptidesView';
38
38
  grok.shell.windows.showProperties = true;
39
39
 
@@ -86,14 +86,12 @@ export async function Peptides() {
86
86
  //input: column col {semType: alignedSequence}
87
87
  //output: widget result
88
88
  export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
89
- if (col.getTag('isAnalysisApplicable') === 'false')
89
+ if (!(col.temp['isAnalysisApplicable'] ?? true))
90
90
  return new DG.Widget(ui.divText('Analysis is not applicable'));
91
91
 
92
- view = (grok.shell.v as DG.TableView);
93
- tableGrid = view.grid;
94
- currentDf = col.dataFrame;
95
- alignedSequenceCol = col;
96
- return await analyzePeptidesWidget(col, view, tableGrid, currentDf);
92
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
93
+ getOrDefineWIP(currentView, currentGrid, currentTable, col);
94
+ return await analyzePeptidesWidget(col, currentView, currentGrid, currentTable);
97
95
  }
98
96
 
99
97
  //name: peptide-sar-viewer
@@ -143,7 +141,9 @@ export async function peptideMolecule(peptide: string): Promise<DG.Widget> {
143
141
  //input: string aar {semType: aminoAcids}
144
142
  //output: widget result
145
143
  export async function peptideMolecule2(aar: string): Promise<DG.Widget> {
146
- const peptide = alignedSequenceCol.get(currentDf.currentRowIdx);
144
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
145
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
146
+ const peptide = alignedSequenceColumn.get(currentTable.currentRowIdx);
147
147
  return await peptideMolecule(peptide);
148
148
  }
149
149
 
@@ -182,8 +182,10 @@ export function logov() {
182
182
  //input: string monomer {semType: aminoAcids}
183
183
  //output: widget result
184
184
  export function manualAlignment(monomer: string) {
185
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
186
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
185
187
  //TODO: recalculate Molfile and Molecule panels on sequence update
186
- return manualAlignmentWidget(alignedSequenceCol, currentDf);
188
+ return manualAlignmentWidget(alignedSequenceColumn, currentTable);
187
189
  }
188
190
 
189
191
  //name: Peptide Space
@@ -191,7 +193,9 @@ export function manualAlignment(monomer: string) {
191
193
  //input: column col {semType: alignedSequence}
192
194
  //output: widget result
193
195
  export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
194
- const widget = new PeptideSimilaritySpaceWidget(col, view ?? grok.shell.v);
196
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
197
+ getOrDefineWIP(currentView, currentGrid, currentTable, col);
198
+ const widget = new PeptideSimilaritySpaceWidget(col, currentView);
195
199
  return await widget.draw();
196
200
  }
197
201
 
@@ -209,7 +213,9 @@ export async function peptideMolfile(peptide: string): Promise<DG.Widget> {
209
213
  //input: string aar { semType: aminoAcids }
210
214
  //output: widget result
211
215
  export async function peptideMolfile2(aar: string): Promise<DG.Widget> {
212
- const peptide = alignedSequenceCol.get(currentDf.currentRowIdx);
216
+ [currentView, currentGrid, currentTable, alignedSequenceColumn] =
217
+ getOrDefineWIP(currentView, currentGrid, currentTable, alignedSequenceColumn);
218
+ const peptide = alignedSequenceColumn.get(currentTable.currentRowIdx);
213
219
  return await peptideMolfile(peptide);
214
220
  }
215
221
 
@@ -218,10 +224,7 @@ export async function peptideMolfile2(aar: string): Promise<DG.Widget> {
218
224
  //input: column col {semType: alignedSequence}
219
225
  //output: dataframe result
220
226
  export async function multipleSequenceAlignment(col: DG.Column): Promise<DG.DataFrame> {
221
- const msaCol = await runKalign(col, true);
222
- const table = col.dataFrame;
223
- table.columns.add(msaCol);
224
- return table;
227
+ return await msaWidget(col);
225
228
  }
226
229
 
227
230
  //name: Substitution
@@ -229,43 +232,7 @@ export async function multipleSequenceAlignment(col: DG.Column): Promise<DG.Data
229
232
  //input: dataframe table {semType: Substitution}
230
233
  //output: widget result
231
234
  export async function peptideSubstitution(table: DG.DataFrame): Promise<DG.Widget> {
232
- if (!table) {
233
- return new DG.Widget(ui.label('No difference'));
234
- }
235
- const peptideLength = 17;
236
- let initialCol: DG.Column = table.columns.byName('Initial');
237
- let substitutedCol: DG.Column = table.columns.byName('Substituted');
238
- let substCounts = [];
239
- let cnt = 0;
240
-
241
- for (let i = 0; i < initialCol.length; ++i) {
242
- const initialPeptide: string = initialCol.get(i);
243
- const substPeptide: string = substitutedCol.get(i);
244
- const concat = initialPeptide + '#' + substPeptide;
245
-
246
- initialCol.set(i, concat);
247
-
248
- const initialAminos = initialPeptide.split('-');
249
- const substAminos = substPeptide.split('-');
250
-
251
- for (let j = 0; j < peptideLength; ++j) {
252
- if (initialAminos[j] != substAminos[j])
253
- substCounts[cnt++] = j;
254
- }
255
- }
256
-
257
- const countCol = DG.Column.fromInt32Array('substCounts', substCounts as unknown as Int32Array);
258
- const df = DG.DataFrame.fromColumns([countCol]);
259
- const barchart = df.plot.histogram({value: 'substCounts'});
260
- if (barchart) {
261
- barchart.root.style.width = '200px';
262
- barchart.root.style.marginLeft = '30px';
263
- }
264
-
265
- initialCol.semType = 'alignedSequenceDifference';
266
- initialCol.name = 'Substitution';
267
- table.columns.remove('Substituted');
268
- return new DG.Widget(ui.div([barchart?.root, table.plot.grid().root]));
235
+ return substTableWidget(table);
269
236
  }
270
237
 
271
238
  //name: alignedSequenceDifferenceCellRenderer
@@ -274,4 +241,17 @@ export async function peptideSubstitution(table: DG.DataFrame): Promise<DG.Widge
274
241
  //output: grid_cell_renderer result
275
242
  export function alignedSequenceDifferenceCellRenderer() {
276
243
  return new AlignedSequenceDifferenceCellRenderer();
277
- }
244
+ }
245
+
246
+ function getOrDefineWIP(
247
+ view?: DG.TableView, grid?: DG.Grid, dataframe?: DG.DataFrame, column?: DG.Column | null,
248
+ ): [DG.TableView, DG.Grid, DG.DataFrame, DG.Column] {
249
+ view ??= (grok.shell.v as DG.TableView);
250
+ grid ??= view.grid;
251
+ dataframe ??= grok.shell.t;
252
+ column ??= (dataframe.columns as DG.ColumnList).bySemType('alignedSequence');
253
+ if (column === null)
254
+ throw new Error('Table does not contain aligned sequence columns');
255
+
256
+ return [view, grid, dataframe, column];
257
+ }
package/src/peptides.ts CHANGED
@@ -1,22 +1,165 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import {createPeptideSimilaritySpaceViewer} from './utils/peptide-similarity-space';
4
- import {addViewerToHeader} from './viewers/stacked-barchart-viewer';
5
- import {model} from './model';
4
+ import {PeptidesModel} from './model';
6
5
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
7
- // import $ from 'cash-dom';
8
-
9
- /**
10
- * Peptides controller class.
11
- *
12
- * @export
13
- * @class Peptides
14
- */
15
- export class Peptides {
16
- private static _model = model;
17
-
18
- static async recalculate() {
19
- await Peptides._model.updateDefault();
6
+ import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
7
+ import {SubstViewer} from './viewers/subst-viewer';
8
+ import {ChemPalette} from './utils/chem-palette';
9
+ import {Observable} from 'rxjs';
10
+
11
+ type viewerTypes = SARViewer | SARViewerVertical | SubstViewer;
12
+ export class PeptidesController {
13
+ private static _controllerName: string = 'peptidesController';
14
+ private helpUrl = '/help/domains/bio/peptides.md';
15
+ private _dataFrame: DG.DataFrame;
16
+ private _model: PeptidesModel;
17
+
18
+ private constructor(dataFrame: DG.DataFrame) {
19
+ this._dataFrame = dataFrame;
20
+ this._model = PeptidesModel.getOrInit(this._dataFrame);
21
+ // this.getOrInitModel(this._dataFrame);
22
+ }
23
+
24
+ static getInstance(dataFrame: DG.DataFrame): PeptidesController {
25
+ dataFrame.temp[PeptidesController.controllerName] ??= new PeptidesController(dataFrame);
26
+ return dataFrame.temp[PeptidesController.controllerName];
27
+ }
28
+
29
+ static get controllerName() {
30
+ return PeptidesController._controllerName;
31
+ }
32
+
33
+ // getOrInitModel(): PeptidesModel {
34
+ // this._model ??= PeptidesModel.getOrInit(this._dataFrame);
35
+ // return this._model;
36
+ // }
37
+
38
+ get onStatsDataFrameChanged(): Observable<DG.DataFrame> {
39
+ return this._model.onStatsDataFrameChanged;
40
+ }
41
+
42
+ get onSARGridChanged(): Observable<DG.Grid> {
43
+ return this._model.onSARGridChanged;
44
+ }
45
+
46
+ get onSARVGridChanged(): Observable<DG.Grid> {
47
+ return this._model.onSARVGridChanged;
48
+ }
49
+
50
+ get onGroupMappingChanged(): Observable<StringDictionary> {
51
+ return this._model.onGroupMappingChanged;
52
+ }
53
+
54
+ get onSubstFlagChanged(): Observable<boolean> {
55
+ return this._model.onSubstFlagChanged;
56
+ }
57
+
58
+ async updateDefault() {
59
+ await this._model.updateDefault();
60
+ }
61
+
62
+ async updateData(
63
+ dataFrame: DG.DataFrame | null, activityCol: string | null, activityScaling: string | null,
64
+ sourceGrid: DG.Grid | null, twoColorMode: boolean | null, initialBitset: DG.BitSet | null,
65
+ grouping: boolean | null) {
66
+ await this._model.updateData(
67
+ dataFrame, activityCol, activityScaling, sourceGrid, twoColorMode, initialBitset, grouping);
68
+ }
69
+
70
+ static async scaleActivity(
71
+ activityScaling: string, activityColumn: string, activityColumnScaled: string, df: DG.DataFrame,
72
+ ): Promise<[DG.DataFrame, string]> {
73
+ // const df = sourceGrid.dataFrame!;
74
+ const tempDf = df.clone(null, [activityColumn]);
75
+
76
+ let formula = '${' + activityColumn + '}';
77
+ let newColName = activityColumn;
78
+ switch (activityScaling) {
79
+ case 'none':
80
+ break;
81
+ case 'lg':
82
+ formula = `Log10(${formula})`;
83
+ newColName = `Log10(${newColName})`;
84
+ break;
85
+ case '-lg':
86
+ formula = `-1*Log10(${formula})`;
87
+ newColName = `-Log10(${newColName})`;
88
+ break;
89
+ default:
90
+ throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
91
+ }
92
+
93
+ await (tempDf.columns as DG.ColumnList).addNewCalculated(activityColumnScaled, formula);
94
+
95
+ return [tempDf, newColName];
96
+ }
97
+
98
+ static splitAlignedPeptides(peptideColumn: DG.Column, filter: boolean = true): [DG.DataFrame, number[]] {
99
+ const splitPeptidesArray: string[][] = [];
100
+ let currentSplitPeptide: string[];
101
+ let modeMonomerCount = 0;
102
+ let currentLength;
103
+ const colLength = peptideColumn.length;
104
+
105
+ // splitting data
106
+ const monomerLengths: {[index: string]: number} = {};
107
+ for (let i = 0; i < colLength; i++) {
108
+ currentSplitPeptide = peptideColumn.get(i).split('-').map((value: string) => value ? value : '-');
109
+ splitPeptidesArray.push(currentSplitPeptide);
110
+ currentLength = currentSplitPeptide.length;
111
+ monomerLengths[currentLength + ''] =
112
+ monomerLengths[currentLength + ''] ? monomerLengths[currentLength + ''] + 1 : 1;
113
+ }
114
+ //@ts-ignore: what I do here is converting string to number the most effective way I could find. parseInt is slow
115
+ modeMonomerCount = 1 * Object.keys(monomerLengths).reduce((a, b) => monomerLengths[a] > monomerLengths[b] ? a : b);
116
+
117
+ // making sure all of the sequences are of the same size
118
+ // and marking invalid sequences
119
+ let nTerminal: string;
120
+ const invalidIndexes: number[] = [];
121
+ let splitColumns: string[][] = Array.from({length: modeMonomerCount}, (_) => []);
122
+ modeMonomerCount--; // minus N-terminal
123
+ for (let i = 0; i < colLength; i++) {
124
+ currentSplitPeptide = splitPeptidesArray[i];
125
+ nTerminal = currentSplitPeptide.pop()!; // it is guaranteed that there will be at least one element
126
+ currentLength = currentSplitPeptide.length;
127
+ if (currentLength !== modeMonomerCount)
128
+ invalidIndexes.push(i);
129
+
130
+ for (let j = 0; j < modeMonomerCount; j++)
131
+ splitColumns[j].push(j < currentLength ? currentSplitPeptide[j] : '-');
132
+
133
+ splitColumns[modeMonomerCount].push(nTerminal);
134
+ }
135
+ modeMonomerCount--; // minus C-terminal
136
+
137
+ //create column names list
138
+ const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1 }`);
139
+ columnNames.splice(0, 0, 'N-terminal');
140
+ columnNames.push('C-terminal');
141
+
142
+ // filter out the columns with the same values
143
+ if (filter) {
144
+ splitColumns = splitColumns.filter((positionArray, index) => {
145
+ const isRetained = new Set(positionArray).size > 1;
146
+ if (!isRetained)
147
+ columnNames.splice(index, 1);
148
+
149
+ return isRetained;
150
+ });
151
+ }
152
+
153
+ return [
154
+ DG.DataFrame.fromColumns(splitColumns.map((positionArray, index) => {
155
+ return DG.Column.fromList('string', columnNames[index], positionArray);
156
+ })),
157
+ invalidIndexes,
158
+ ];
159
+ }
160
+
161
+ static getChemPalette() {
162
+ return ChemPalette;
20
163
  }
21
164
 
22
165
  /**
@@ -30,12 +173,17 @@ export class Peptides {
30
173
  * @memberof Peptides
31
174
  */
32
175
  async init(
33
- tableGrid: DG.Grid,
34
- view: DG.TableView,
35
- currentDf: DG.DataFrame,
36
- options: StringDictionary,
37
- col: DG.Column,
38
- ) {
176
+ tableGrid: DG.Grid, view: DG.TableView, options: StringDictionary, col: DG.Column,
177
+ originalDfColumns: string[]) {
178
+ function adjustCellSize(grid: DG.Grid) {
179
+ const colNum = grid.columns.length;
180
+ for (let i = 0; i < colNum; ++i) {
181
+ const iCol = grid.columns.byIndex(i)!;
182
+ iCol.width = isNaN(parseInt(iCol.name)) ? 50 : 40;
183
+ }
184
+ grid.props.rowHeight = 20;
185
+ }
186
+
39
187
  for (let i = 0; i < tableGrid.columns.length; i++) {
40
188
  const aarCol = tableGrid.columns.byIndex(i);
41
189
  if (aarCol &&
@@ -47,48 +195,31 @@ export class Peptides {
47
195
  }
48
196
  }
49
197
 
50
- const initialFiter = currentDf.filter.clone();
51
- const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
52
- const originalDfName = currentDf.name;
198
+ const originalDfName = this._dataFrame.name;
199
+ const dockManager = view.dockManager;
53
200
 
54
- // const substViewer = view.addViewer(
55
- // 'substitution-analysis-viewer', {'activityColumnName': `${options['activityColumnName']}Scaled`},
56
- // );
57
- // const substNode = view.dockManager.dock(substViewer, DG.DOCK_TYPE.RIGHT, null, 'Substitution Analysis');
201
+ const sarViewer = await this._dataFrame.plot.fromType('peptide-sar-viewer', options) as SARViewer;
202
+ sarViewer.helpUrl = this.helpUrl;
58
203
 
59
- // const layout1 = view.saveLayout();
60
- // view.dockManager.close(substNode);
204
+ const sarViewerVertical = await this._dataFrame.plot.fromType('peptide-sar-viewer-vertical') as SARViewerVertical;
205
+ sarViewerVertical.helpUrl = this.helpUrl;
61
206
 
62
- const helpUrl = '/help/domains/bio/peptides.md';
207
+ const sarViewersGroup: viewerTypes[] = [sarViewer, sarViewerVertical];
63
208
 
64
- const sarViewer = view.addViewer('peptide-sar-viewer', options);
65
- sarViewer.helpUrl = helpUrl;
66
- const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
209
+ const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
210
+ this._dataFrame, col, 't-SNE', 'Levenshtein', 100, view, `${options['activityColumnName']}Scaled`);
211
+ dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space viewer');
67
212
 
68
- const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
69
- sarViewerVertical.helpUrl = helpUrl;
70
- const sarVNode = view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
213
+ let nodeList = dockViewers(sarViewersGroup, DG.DOCK_TYPE.RIGHT, dockManager, DG.DOCK_TYPE.DOWN);
214
+
215
+ const substViewer = await this._dataFrame.plot.fromType(
216
+ 'substitution-analysis-viewer', {'activityColumnName': `${options['activityColumnName']}Scaled`}) as SubstViewer;
217
+ const substViewersGroup = [substViewer];
71
218
 
72
- const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
73
- currentDf,
74
- col,
75
- 't-SNE',
76
- 'Levenshtein',
77
- 100,
78
- view,
79
- `${options['activityColumnName']}Scaled`,
80
- );
81
- const psNode = view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
82
-
83
- // const layout2 = view.saveLayout();
84
-
85
- const nodeList = [sarNode, sarVNode, psNode];
86
-
87
- const StackedBarchartProm = currentDf.plot.fromType('StackedBarChartAA');
88
- addViewerToHeader(tableGrid, StackedBarchartProm);
89
219
  tableGrid.props.allowEdit = false;
220
+ adjustCellSize(tableGrid);
90
221
 
91
- const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
222
+ const hideIcon = ui.iconFA('window-close', () => {
92
223
  const viewers = [];
93
224
  for (const viewer of view.viewers) {
94
225
  if (viewer.type !== DG.VIEWER.GRID)
@@ -96,76 +227,55 @@ export class Peptides {
96
227
  }
97
228
  viewers.forEach((v) => v.close());
98
229
 
99
- const cols = (currentDf.columns as DG.ColumnList);
230
+ const cols = (this._dataFrame.columns as DG.ColumnList);
100
231
  for (const colName of cols.names()) {
101
232
  if (!originalDfColumns.includes(colName))
102
233
  cols.remove(colName);
103
234
  }
104
235
 
105
- currentDf.selection.setAll(false);
106
- currentDf.filter.setAll(true);
236
+ this._dataFrame.selection.setAll(false);
237
+ this._dataFrame.filter.setAll(true);
107
238
 
108
239
  tableGrid.setOptions({'colHeaderHeight': 20});
109
240
  tableGrid.columns.setVisible(originalDfColumns);
110
241
  tableGrid.props.allowEdit = true;
111
- currentDf.name = originalDfName;
242
+ this._dataFrame.name = originalDfName;
112
243
 
113
244
  view.setRibbonPanels(ribbonPanels);
114
245
  }, 'Close viewers and restore dataframe');
115
246
 
116
247
  let isSA = false;
117
- //TODO: fix layouts
118
- // const switchViewers = ui.iconFA('toggle-on', () => {
119
- // if (isSA) {
120
- // view.loadLayout(layout1);
121
- // $(switchViewers).removeClass('fa-toggle-off');
122
- // $(switchViewers).addClass('fa-toggle-on');
123
- // } else {
124
- // view.loadLayout(layout2);
125
- // $(switchViewers).removeClass('fa-toggle-on');
126
- // $(switchViewers).addClass('fa-toggle-off');
127
- // }
128
- // isSA = !isSA;
129
- // });
130
- const switchViewers = ui.iconFA('toggle-on', async () => {
131
- currentDf.filter.copyFrom(initialFiter);
132
- currentDf.selection.setAll(false);
133
- nodeList.forEach((node) => view.dockManager.close(node));
134
- nodeList.length = 0;
135
- if (isSA) {
136
- const sarViewer = view.addViewer('peptide-sar-viewer', options);
137
- sarViewer.helpUrl = helpUrl;
138
- const sarNode = view.dockManager.dock(sarViewer, DG.DOCK_TYPE.DOWN, null, 'SAR Viewer');
139
-
140
- const sarViewerVertical = view.addViewer('peptide-sar-viewer-vertical');
141
- sarViewerVertical.helpUrl = helpUrl;
142
- const sarVNode = view.dockManager.dock(sarViewerVertical, DG.DOCK_TYPE.RIGHT, sarNode, 'SAR Vertical Viewer');
143
-
144
- const peptideSpaceViewer = await createPeptideSimilaritySpaceViewer(
145
- currentDf, col, 't-SNE', 'Levenshtein', 100, view, `${options['activityColumnName']}Scaled`);
146
- const psNode = view.dockManager.dock(
147
- peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
148
-
149
- nodeList.push(sarNode);
150
- nodeList.push(sarVNode);
151
- nodeList.push(psNode);
152
-
153
- $(switchViewers).removeClass('fa-toggle-off');
154
- $(switchViewers).addClass('fa-toggle-on');
155
- } else {
156
- const substViewer = view.addViewer(
157
- 'substitution-analysis-viewer', {'activityColumnName': `${options['activityColumnName']}Scaled`},
158
- );
159
- substViewer.helpUrl = helpUrl;
160
- nodeList.push(view.dockManager.dock(substViewer, DG.DOCK_TYPE.DOWN, null, 'Substitution Analysis'));
161
- $(switchViewers).removeClass('fa-toggle-on');
162
- $(switchViewers).addClass('fa-toggle-off');
163
- }
248
+ const switchViewers = ui.iconFA('toggle-on', () => {
249
+ $(switchViewers).toggleClass('fa-toggle-off').toggleClass('fa-toggle-on');
250
+ nodeList?.forEach((node) => {
251
+ view.dockManager.close(node);
252
+ node.container.destroy();
253
+ });
254
+ const getCurrentViewerGroup = () => isSA ? substViewersGroup : sarViewersGroup;
255
+ getCurrentViewerGroup().forEach((v) => v.removeFromView());
164
256
  isSA = !isSA;
165
- });
257
+ nodeList = dockViewers(getCurrentViewerGroup(), DG.DOCK_TYPE.LEFT, dockManager, DG.DOCK_TYPE.DOWN);
258
+ }, 'Toggle viewer group');
166
259
 
167
260
  const ribbonPanels = view.getRibbonPanels();
168
261
  view.setRibbonPanels([[hideIcon, switchViewers]]);
169
- // view.setRibbonPanels([[hideIcon]]);
170
262
  }
171
263
  }
264
+
265
+ function dockViewers(
266
+ viewerList: viewerTypes[], attachDirection: DG.DockType, dockManager: DG.DockManager,
267
+ initialAttachDirection?: DG.DockType): DG.DockNode[] | null {
268
+ const viewerListLength = viewerList.length;
269
+ if (viewerListLength === 0)
270
+ return null;
271
+
272
+ let currentViewer = viewerList[0];
273
+ const nodeList = [dockManager.dock(currentViewer, initialAttachDirection, null, currentViewer.name ?? '')];
274
+ const ratio = 1 / viewerListLength;
275
+
276
+ for (let i = 1; i < viewerListLength; i++) {
277
+ currentViewer = viewerList[i];
278
+ nodeList.push(dockManager.dock(currentViewer, attachDirection, nodeList[i - 1], currentViewer.name ?? '', ratio));
279
+ }
280
+ return nodeList;
281
+ }
@@ -11,7 +11,7 @@ import {aligned1} from './test-data';
11
11
 
12
12
  import * as DG from 'datagrok-api/dg';
13
13
  import * as grok from 'datagrok-api/grok';
14
- import { StringMetrics } from '@datagrok-libraries/ml/src/typed-metrics';
14
+ import {StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
15
15
 
16
16
  export const _package = new DG.Package();
17
17
 
@@ -1,9 +1,9 @@
1
1
  import {after, before, category, test} from '@datagrok-libraries/utils/src/test';
2
2
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
3
- import {splitAlignedPeptides} from '../utils/split-aligned';
3
+ // import {splitAlignedPeptides} from '../utils/split-aligned';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
  import * as grok from 'datagrok-api/grok';
6
- import {Peptides} from '../peptides';
6
+ import {PeptidesController} from '../peptides';
7
7
  import {describe} from '../describe';
8
8
  import {analyzePeptidesWidget} from '../widgets/analyze-peptides';
9
9
  import {manualAlignmentWidget} from '../widgets/manual-alignment';
@@ -52,7 +52,7 @@ category('peptides', async () => {
52
52
  });
53
53
 
54
54
  test('utils.split-sequence', async () => {
55
- splitAlignedPeptides(peptidesDf.getCol('AlignedSequence'));
55
+ PeptidesController.splitAlignedPeptides(peptidesDf.getCol('AlignedSequence'));
56
56
  });
57
57
 
58
58
  test('describe', async () => {
@@ -61,9 +61,9 @@ category('peptides', async () => {
61
61
  DG.BitSet.create(peptidesDf.rowCount, (i) => i % 2 === 0), true);
62
62
  });
63
63
 
64
- test('Peptides-class', async () => {
65
- const peptides = new Peptides();
66
- peptides.init(peptidesGrid, pepView, peptidesDf, options, asCol);
64
+ test('Peptides-controller', async () => {
65
+ const peptides = PeptidesController.getInstance(peptidesDf);
66
+ peptides.init(peptidesGrid, pepView, options, asCol, peptidesDf.columns.names());
67
67
  });
68
68
 
69
69
  test('panel.peptides', async () => {
@@ -6,7 +6,7 @@ import {
6
6
  createDimensinalityReducingWorker,
7
7
  } from '@datagrok-libraries/ml/src/workers/dimensionality-reducing-worker-creator';
8
8
  import {runKalign} from '../utils/multiple-sequence-alignment';
9
- import { StringMetrics } from '@datagrok-libraries/ml/src/typed-metrics';
9
+ import {StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
10
10
 
11
11
  /**
12
12
  * Tests if a table has non zero rows and columns.
@@ -48,7 +48,8 @@ export async function _testDimensionalityReducer(columnData: Array<string>, meth
48
48
  let embcols;
49
49
 
50
50
  try {
51
- embcols = await createDimensinalityReducingWorker({data: columnData, metric: measure as StringMetrics}, method, cyclesCount);
51
+ embcols = await createDimensinalityReducingWorker(
52
+ {data: columnData, metric: measure as StringMetrics}, method, cyclesCount);
52
53
  } catch (error) {
53
54
  noException = false;
54
55
  }