@datagrok/peptides 1.17.11 → 1.17.13

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
3
  "friendlyName": "Peptides",
4
- "version": "1.17.11",
4
+ "version": "1.17.13",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -13,11 +13,11 @@
13
13
  "directory": "packages/Peptides"
14
14
  },
15
15
  "dependencies": {
16
- "@datagrok-libraries/bio": "^5.39.14",
17
- "@datagrok-libraries/ml": "^6.4.10",
18
- "@datagrok-libraries/statistics": "^1.2.11",
19
- "@datagrok-libraries/utils": "^4.1.36",
20
- "@datagrok-libraries/tutorials": "^1.3.11",
16
+ "@datagrok-libraries/bio": "^5.40.0",
17
+ "@datagrok-libraries/ml": "^6.4.13",
18
+ "@datagrok-libraries/statistics": "^1.2.12",
19
+ "@datagrok-libraries/utils": "^4.1.45",
20
+ "@datagrok-libraries/tutorials": "^1.3.12",
21
21
  "@datagrok-libraries/math": "^1.0.7",
22
22
  "cash-dom": "latest",
23
23
  "datagrok-api": "^1.17.9",
@@ -50,7 +50,7 @@
50
50
  "link-statistics": "npm link @datagrok-libraries/statistics",
51
51
  "link-ml": "npm link @datagrok-libraries/ml",
52
52
  "link-bio": "npm link @datagrok-libraries/bio",
53
- "link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/ml @datagrok-libraries/bio @datagrok-libraries/statistics @datagrok-libraries/tutorials",
53
+ "link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/math @datagrok-libraries/ml @datagrok-libraries/bio @datagrok-libraries/statistics @datagrok-libraries/tutorials",
54
54
  "install-dependencies": "npm install",
55
55
  "debug-peptides": "grok publish",
56
56
  "release-peptides": "grok publish --release",
@@ -67,7 +67,7 @@
67
67
  "test": "grok test",
68
68
  "test-dev": "grok test --host dev",
69
69
  "test-local": "grok test --host localhost",
70
- "build-all": "npm --prefix ./../../js-api run build && npm --prefix ./../../libraries/utils run build && npm --prefix ./../../libraries/ml run build && npm --prefix ./../../libraries/bio run build && npm --prefix ./../../libraries/statistics run build && npm --prefix ./../../libraries/tutorials run build && npm run build"
70
+ "build-all": "npm --prefix ./../../js-api run build && npm --prefix ./../../libraries/utils run build && npm --prefix ./../../libraries/math run build && npm --prefix ./../../libraries/ml run build && npm --prefix ./../../libraries/bio run build && npm --prefix ./../../libraries/statistics run build && npm --prefix ./../../libraries/tutorials run build && npm run build"
71
71
  },
72
72
  "canEdit": [
73
73
  "Developers"
package/src/model.ts CHANGED
@@ -13,7 +13,7 @@ import {DistanceMatrix} from '@datagrok-libraries/ml/src/distance-matrix';
13
13
  import {BitArrayMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
14
14
  import {TAGS as _treeTAGS} from '@datagrok-libraries/bio/src/trees';
15
15
  import BitArray from '@datagrok-libraries/utils/src/bit-array';
16
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
16
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
17
17
  import wu from 'wu';
18
18
  import * as rxjs from 'rxjs';
19
19
  import $ from 'cash-dom';
@@ -53,12 +53,14 @@ import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter'
53
53
  import {getDbscanWorker} from '@datagrok-libraries/math';
54
54
  import {markovCluster} from '@datagrok-libraries/ml/src/MCL/clustering-view';
55
55
  import {DistanceAggregationMethods} from '@datagrok-libraries/ml/src/distance-matrix/types';
56
+ import {ClusterMaxActivityViewer, IClusterMaxActivity} from './viewers/cluster-max-activity-viewer';
56
57
 
57
58
  export enum VIEWER_TYPE {
58
59
  MONOMER_POSITION = 'Monomer-Position',
59
60
  MOST_POTENT_RESIDUES = 'Most Potent Residues',
60
61
  LOGO_SUMMARY_TABLE = 'Logo Summary Table',
61
62
  DENDROGRAM = 'Dendrogram',
63
+ CLUSTER_MAX_ACTIVITY = 'Cluster Max Activity',
62
64
  }
63
65
 
64
66
  export type CachedWebLogoTooltip = { bar: string, tooltip: HTMLDivElement | null };
@@ -190,6 +192,9 @@ export class PeptidesModel {
190
192
  case 'showDendrogram':
191
193
  updateVars.add('dendrogram');
192
194
  break;
195
+ case 'showClusterMaxActivity':
196
+ updateVars.add('clusterMaxActivity');
197
+ break;
193
198
  case 'showSequenceSpace':
194
199
  updateVars.add('showSequenceSpace');
195
200
  break;
@@ -250,6 +255,10 @@ export class PeptidesModel {
250
255
  case 'dendrogram':
251
256
  this.settings!.showDendrogram ? this.addDendrogram() : this.closeViewer(VIEWER_TYPE.DENDROGRAM);
252
257
  break;
258
+ case 'clusterMaxActivity':
259
+ this.settings!.showClusterMaxActivity ? this.addClusterMaxActivityViewer() :
260
+ this.closeViewer(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY);
261
+ break;
253
262
  case 'logoSummaryTable':
254
263
  this.settings!.showLogoSummaryTable ? this.addLogoSummaryTable() :
255
264
  this.closeViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE);
@@ -1115,6 +1124,22 @@ export class PeptidesModel {
1115
1124
  logoSummaryTable.viewerGrid.invalidate();
1116
1125
  }
1117
1126
 
1127
+ async addClusterMaxActivityViewer(viewerProperties?: IClusterMaxActivity): Promise<void> {
1128
+ const potentialClusterCol = this._mclCols?.find((colName) => colName.toLowerCase().startsWith('cluster (mcl)')) ??
1129
+ (this.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable | null)?.clustersColumnName ??
1130
+ this._sequenceSpaceCols?.find((colName) => colName.toLowerCase().startsWith('cluster'));
1131
+ viewerProperties ??= {
1132
+ activityColumnName: this.settings!.activityColumnName,
1133
+ clusterColumnName: potentialClusterCol ?? wu(this.df.columns.categorical).next().value?.name,
1134
+ activityTarget: C.ACTIVITY_TARGET.HIGH,
1135
+ };
1136
+ const _clusterMaxActivity = await this.df.plot
1137
+ .fromType(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, viewerProperties) as ClusterMaxActivityViewer;
1138
+ const lstNode = this.findViewerNode(VIEWER_TYPE.LOGO_SUMMARY_TABLE) ?? null;
1139
+ this.analysisView.dockManager.dock(_clusterMaxActivity, lstNode ? DG.DOCK_TYPE.DOWN: DG.DOCK_TYPE.RIGHT,
1140
+ lstNode, VIEWER_TYPE.CLUSTER_MAX_ACTIVITY);
1141
+ }
1142
+
1118
1143
  /**
1119
1144
  * Adds Monomer-Position viewer to the analysis view
1120
1145
  * @param {ISARViewer} [viewerProperties] - Viewer properties
@@ -1231,13 +1256,13 @@ export class PeptidesModel {
1231
1256
  const seqCol = this.df.getCol(this.settings!.sequenceColumnName!);
1232
1257
  this.settings!.mclSettings ??= new type.MCLSettings();
1233
1258
  const mclParams = this.settings?.mclSettings;
1234
-
1235
1259
  let counter = 0;
1236
- const addedColCount = 4;
1260
+ const addedColCount = 5; // embedx, embedy, cluster, cluster size and connectivity count
1237
1261
  const columnAddedSub = this.df.onColumnsAdded.subscribe((colArgs: DG.ColumnsArgs) => {
1238
1262
  for (const col of colArgs.columns) {
1239
- if (col.name.toLowerCase().startsWith('embed') ||
1240
- col.name.toLowerCase().startsWith('cluster')) {
1263
+ if ((col.name.toLowerCase().startsWith('embed') ||
1264
+ col.name.toLowerCase().startsWith('cluster') ||
1265
+ col.name.toLowerCase().startsWith('connectivity')) && col.name.toLowerCase().includes('mcl')) {
1241
1266
  const gridCol = this.analysisView.grid.col(col.name);
1242
1267
  if (gridCol == null || this._mclCols.includes(col.name))
1243
1268
  continue;
@@ -1276,7 +1301,7 @@ export class PeptidesModel {
1276
1301
  }], mclParams!.threshold, mclParams!.maxIterations,
1277
1302
  );
1278
1303
  mclAdditionSub.unsubscribe();
1279
- this._mclViewer = mclViewer ?? null;
1304
+ this._mclViewer = mclViewer?.sc ?? null;
1280
1305
  }
1281
1306
 
1282
1307
  /**
@@ -1293,13 +1318,13 @@ export class PeptidesModel {
1293
1318
  this._sequenceSpaceCols.forEach((col) => this.df.columns.remove(col));
1294
1319
  this._sequenceSpaceCols = [];
1295
1320
  let seqCol = this.df.getCol(this.settings!.sequenceColumnName!);
1296
- const uh = UnitsHandler.getOrCreate(seqCol);
1297
- const isHelm = uh.isHelm();
1321
+ const sh = SeqHandler.forColumn(seqCol);
1322
+ const isHelm = sh.isHelm();
1298
1323
  if (isHelm) {
1299
1324
  try {
1300
1325
  grok.shell.warning('Column is in HELM notation. Sequences space will linearize sequences from position 0 ' +
1301
1326
  'prior to analysis');
1302
- const linearCol = uh.convert(NOTATION.SEPARATOR, '/');
1327
+ const linearCol = sh.convert(NOTATION.SEPARATOR, '/');
1303
1328
  const newName = this.df.columns.getUnusedName(`Separator(${seqCol.name})`);
1304
1329
  linearCol.name = newName;
1305
1330
  this.df.columns.add(linearCol, true);
package/src/package.ts CHANGED
@@ -13,6 +13,7 @@ import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-wo
13
13
  import {PeptidesModel} from './model';
14
14
  import {macromoleculeSarFastaDemoUI} from './demo/fasta';
15
15
  import {u2} from '@datagrok-libraries/utils/src/u2';
16
+ import {ClusterMaxActivityViewer} from './viewers/cluster-max-activity-viewer';
16
17
 
17
18
  let monomerWorks: MonomerWorks | null = null;
18
19
  let treeHelper: ITreeHelper;
@@ -129,6 +130,13 @@ export function logoSummaryTable(): LogoSummaryTable {
129
130
  return new LogoSummaryTable();
130
131
  }
131
132
 
133
+ //name: Cluster Max Activity
134
+ //tags: viewer
135
+ //output: viewer result
136
+ export function clusterMaxActivity(): ClusterMaxActivityViewer {
137
+ return new ClusterMaxActivityViewer();
138
+ }
139
+
132
140
  //name: Manual Alignment
133
141
  //tags: panel, widgets
134
142
  //input: string _monomer {semType: Monomer}
@@ -29,6 +29,7 @@ export interface PeptidesSettings {
29
29
  showMostPotentResidues?: boolean,
30
30
  showLogoSummaryTable?: boolean,
31
31
  showDendrogram?: boolean,
32
+ showClusterMaxActivity?: boolean,
32
33
  showSequenceSpace?: boolean,
33
34
  columns?: AggregationColumns,
34
35
  sequenceSpaceParams: SequenceSpaceParams,
@@ -0,0 +1,228 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as DG from 'datagrok-api/dg';
3
+ import {PeptidesModel, VIEWER_TYPE} from '../model';
4
+ import {Options} from '@datagrok-libraries/utils/src/type-declarations';
5
+ import {ACTIVITY_TARGET, COLUMN_NAME, COLUMNS_NAMES} from '../utils/constants';
6
+ import wu from 'wu';
7
+ import $ from 'cash-dom';
8
+ export const enum ClusterMaxActivityProps {
9
+ CLUSTER_COLUMN = 'cluster',
10
+ ACTIVITY_COLUMN = 'activity',
11
+ COLOR_COLUMN = 'color',
12
+ }
13
+
14
+ export interface IClusterMaxActivity {
15
+ clusterColumnName: string;
16
+ activityColumnName: string;
17
+ colorColumnName?: string;
18
+ activityTarget: ACTIVITY_TARGET;
19
+ }
20
+
21
+
22
+ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMaxActivity {
23
+ _titleHost = ui.divText(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, {id: 'pep-viewer-title'});
24
+ clusterColumnName: string;
25
+ activityColumnName: string;
26
+ colorColumnName: string;
27
+ activityTarget: ACTIVITY_TARGET = ACTIVITY_TARGET.HIGH;
28
+ _scViewer?: DG.ScatterPlotViewer | null;
29
+ viewerError: string = '';
30
+ renderTimeout: NodeJS.Timeout | number | null = null;
31
+ renderDebounceTime = 500;
32
+ static clusterSizeColName = '~cluster.size' as const;
33
+ static maxActivityInClusterSizeColName = '~max.activity.for.cluster.size' as const;
34
+ private scFilterQuery = `\$\{${ClusterMaxActivityViewer.maxActivityInClusterSizeColName}\} == true` as const;
35
+ get scViewer(): DG.ScatterPlotViewer | null {
36
+ if (!this._scViewer)
37
+ this._scViewer = this.createSCViewer();
38
+ return this._scViewer;
39
+ }
40
+ constructor() {
41
+ super();
42
+ this.clusterColumnName = this.column(ClusterMaxActivityProps.CLUSTER_COLUMN, {nullable: false});
43
+ this.activityColumnName = this.column(ClusterMaxActivityProps.ACTIVITY_COLUMN, {nullable: false});
44
+ this.colorColumnName = this.column(ClusterMaxActivityProps.COLOR_COLUMN,
45
+ {nullable: true, defaultValue: null});
46
+ this.activityTarget = this.string(
47
+ 'activityTarget', ACTIVITY_TARGET.HIGH, {choices: [ACTIVITY_TARGET.HIGH, ACTIVITY_TARGET.LOW]},
48
+ ) as ACTIVITY_TARGET;
49
+ }
50
+
51
+ /**
52
+ * Returns PeptidesModel instance that belongs to the attached dataframe.
53
+ * @return - PeptidesModel instance.
54
+ */
55
+ get model(): PeptidesModel {
56
+ return PeptidesModel.getInstance(this.dataFrame);
57
+ }
58
+
59
+ private createSCViewer(): DG.ScatterPlotViewer | null {
60
+ const scatterPlotProps: Partial<DG.IScatterPlotLookSettings> & Options = {
61
+ showXAxis: true,
62
+ showYAxis: true,
63
+ showXSelector: false,
64
+ showYSelector: false,
65
+ showColorSelector: false,
66
+ xAxisType: 'logarithmic',
67
+ yAxisType: 'logarithmic',
68
+ invertYAxis: this.activityTarget === ACTIVITY_TARGET.LOW,
69
+ xColumnName: ClusterMaxActivityViewer.clusterSizeColName,
70
+ markerType: 'circle',
71
+ markerDefaultSize: 10,
72
+ showSizeSelector: false,
73
+ };
74
+ if (this.clusterColumnName == null || this.activityColumnName == null ||
75
+ !this.dataFrame.columns.contains(this.clusterColumnName) ||
76
+ !this.dataFrame.columns.contains(this.activityColumnName)
77
+ ) {
78
+ this.viewerError = 'Please set valid cluster and activity columns';
79
+ return null;
80
+ }
81
+ const activityCol = this.dataFrame.columns.byName(this.activityColumnName);
82
+ const clusterCol = this.dataFrame.columns.byName(this.clusterColumnName);
83
+ const numericColTypes: DG.ColumnType[] =
84
+ [DG.COLUMN_TYPE.FLOAT, DG.COLUMN_TYPE.INT, DG.COLUMN_TYPE.BIG_INT, DG.COLUMN_TYPE.QNUM];
85
+ if (!numericColTypes.includes(activityCol.type)) {
86
+ this.viewerError = 'Activity column should be numeric';
87
+ return null;
88
+ }
89
+ const clusterSizeCol = this.dataFrame.columns.getOrCreate(ClusterMaxActivityViewer.clusterSizeColName,
90
+ DG.TYPE.INT, this.dataFrame.rowCount);
91
+ const clusterSizeMap: {[key: number | string]: number} = {};
92
+ for (let i = 0; i < this.dataFrame.rowCount; i++) {
93
+ const cluster: string | number = clusterCol.get(i);
94
+ if (cluster == null)
95
+ continue;
96
+ clusterSizeMap[cluster] = (clusterSizeMap[cluster] ?? 0) + 1;
97
+ }
98
+ // for (let i = 0; i < this.dataFrame.rowCount; i++) {
99
+ // const cluster: string | number = clusterCol.get(i);
100
+ // if (clusterCol.isNone(i) || !clusterSizeMap[cluster])
101
+ // continue;
102
+ // clusterSizeCol.set(i, clusterSizeMap[cluster]);
103
+ // }
104
+ // clusterSizeCol.init((i) => {
105
+ // const cluster: string | number = clusterCol.get(i);
106
+ // if (clusterCol.isNone(i) || !clusterSizeMap[cluster])
107
+ // return null;
108
+ // return clusterSizeMap[cluster];
109
+ // });
110
+ clusterSizeCol.init((i) => clusterCol.isNone(i) ? null : clusterSizeMap[clusterCol.get(i)] ?? null);
111
+
112
+ if (activityCol.stats.min <= 0)
113
+ scatterPlotProps.yAxisType = 'linear';
114
+
115
+ // create a new column to store max activity for each cluster size
116
+ const maxActivityIndexPerClusterSizeMap: {[key: number]: number} = {};
117
+
118
+ for (let i = 0; i < this.dataFrame.rowCount; i++) {
119
+ const clusterSize: number | null = clusterSizeCol.get(i);
120
+ if (clusterSize == null || clusterSizeCol.isNone(i) || activityCol.isNone(i))
121
+ continue;
122
+ const activity: number = activityCol.get(i);
123
+ const prevMaxActivityIndex = maxActivityIndexPerClusterSizeMap[clusterSize];
124
+ if (prevMaxActivityIndex == null || prevMaxActivityIndex == undefined)
125
+ maxActivityIndexPerClusterSizeMap[clusterSize] = i;
126
+ else {
127
+ if (activity > activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.HIGH)
128
+ maxActivityIndexPerClusterSizeMap[clusterSize] = i;
129
+ else if (activity < activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.LOW)
130
+ maxActivityIndexPerClusterSizeMap[clusterSize] = i;
131
+ }
132
+ }
133
+
134
+ const maxAtivityInClusterSizeCol = this.dataFrame.columns.getOrCreate(
135
+ ClusterMaxActivityViewer.maxActivityInClusterSizeColName, DG.COLUMN_TYPE.BOOL, this.dataFrame.rowCount);
136
+ maxAtivityInClusterSizeCol.init((i) => {
137
+ if (clusterSizeCol.isNone(i))
138
+ return false;
139
+ return i === maxActivityIndexPerClusterSizeMap[clusterSizeCol.get(i)];
140
+ });
141
+ scatterPlotProps.xColumnName = ClusterMaxActivityViewer.clusterSizeColName;
142
+ scatterPlotProps.yColumnName = this.activityColumnName;
143
+ scatterPlotProps.filter = this.scFilterQuery;
144
+ this.viewerError = '';
145
+ const sc = DG.Viewer.scatterPlot(this.dataFrame, scatterPlotProps);
146
+
147
+ return sc;
148
+ }
149
+
150
+ onTableAttached(): void {
151
+ super.onTableAttached();
152
+ const activityCol: DG.Column | null = this.dataFrame?.col(COLUMNS_NAMES.ACTIVITY) ??
153
+ wu(this.dataFrame?.columns.numerical).next()?.value;
154
+ if (activityCol != null)
155
+ this.getProperty(`${ClusterMaxActivityProps.ACTIVITY_COLUMN}${COLUMN_NAME}`)?.set(this, activityCol.name);
156
+
157
+ const clusterCol: DG.Column | null = wu(this.dataFrame?.columns.categorical).next()?.value;
158
+ if (clusterCol != null)
159
+ this.getProperty(`${ClusterMaxActivityProps.CLUSTER_COLUMN}${COLUMN_NAME}`)?.set(this, clusterCol.name);
160
+
161
+ this.render();
162
+
163
+ this.dataFrame.onDataChanged.subscribe(() => {
164
+ // this._scViewer = null;
165
+ // this.render();
166
+
167
+ this.render();
168
+ });
169
+ }
170
+
171
+ render(): void {
172
+ if (this.renderTimeout)
173
+ clearTimeout(this.renderTimeout);
174
+ this.renderTimeout = setTimeout(() => {
175
+ $(this.root).empty();
176
+ const scViewer = this.scViewer;
177
+ if (scViewer == null) {
178
+ this.root.appendChild(ui.divText(this.viewerError ?? 'Error creating scatter plot'));
179
+ return;
180
+ }
181
+ const clusterSizeLabel = ui.div('Cluster Size', {style: {
182
+ alignSelf: 'center',
183
+ color: 'var(--grey-6)',
184
+ marginBottom: '5px'},
185
+ });
186
+ const maxActivityLabel = ui.div(
187
+ this.activityTarget === ACTIVITY_TARGET.HIGH ? 'Maximum Activity' : 'Minimum Activity', {style: {
188
+ color: 'var(--grey-6)',
189
+ alignSelf: 'center',
190
+ textOrientation: 'mixed',
191
+ writingMode: 'tb',
192
+ transform: 'rotate(180deg)',
193
+ marginLeft: '5px',
194
+ }});
195
+ scViewer.props.colorColumnName = this.colorColumnName ?? null;
196
+ this.root.appendChild(
197
+ ui.divH([
198
+ maxActivityLabel,
199
+ ui.divV([
200
+ ui.divH([this._titleHost], {
201
+ style: {
202
+ alignSelf: 'center',
203
+ lineHeight: 'normal',
204
+ },
205
+ }),
206
+ scViewer.root,
207
+ clusterSizeLabel,
208
+ ], {style: {flexGrow: '1'},
209
+ }),
210
+ ]),
211
+ );
212
+ scViewer.root.style.width = '100%';
213
+ //this.root.appendChild(scViewer.root);
214
+ setTimeout(() => {
215
+ scViewer.props.filter = this.scFilterQuery;
216
+ scViewer.invalidateCanvas();
217
+ }, 100);
218
+ }, this.renderDebounceTime);
219
+ }
220
+
221
+ onPropertyChanged(property: DG.Property | null): void {
222
+ super.onPropertyChanged(property);
223
+ if (property?.name !== `${ClusterMaxActivityProps.COLOR_COLUMN}${COLUMN_NAME}`)
224
+ this._scViewer = null;
225
+ this.render();
226
+ }
227
+ }
228
+
@@ -580,7 +580,7 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
580
580
  grid.onCellRender.subscribe(async (gridCellArgs) => {
581
581
  const gridCell = gridCellArgs.cell;
582
582
  const currentRowIdx = gridCell.tableRowIndex;
583
- if (!gridCell.isTableCell || currentRowIdx === null || currentRowIdx === -1)
583
+ if (!gridCell.isTableCell || currentRowIdx == null || currentRowIdx === -1)
584
584
  return;
585
585
 
586
586
 
@@ -5,7 +5,7 @@ import * as DG from 'datagrok-api/dg';
5
5
  import $ from 'cash-dom';
6
6
  import '../styles.css';
7
7
  import {PeptidesModel} from '../model';
8
- import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
8
+ import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
9
9
 
10
10
  /**
11
11
  * Allows to edit sequence and apply changes to the table and analysis.
@@ -18,14 +18,13 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column<string>, cur
18
18
  $(sequenceInput.root).addClass('pep-textinput');
19
19
 
20
20
  const applyChangesBtn = ui.button('Apply', async () => {
21
- const uh = UnitsHandler.getOrCreate(alignedSequenceCol);
21
+ const sh = SeqHandler.forColumn(alignedSequenceCol);
22
22
  const newSequence = sequenceInput.value;
23
- const splitter = uh.getSplitter();
24
- const splitSequence = splitter(newSequence);
23
+ const splitSequence = sh.split(newSequence);
25
24
  const affectedRowIndex = currentDf.currentRowIdx;
26
25
  alignedSequenceCol.set(affectedRowIndex, newSequence);
27
26
  for (let i = 0; i < splitSequence.length; i++) {
28
- const part = splitSequence[i];
27
+ const part = splitSequence.getCanonical(i);
29
28
  if (currentDf.col(i.toString()) !== null)
30
29
  currentDf.set(i.toString(), affectedRowIndex, part);
31
30
  }
@@ -113,6 +113,9 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
113
113
  const isDendrogramEnabled = wu(model.analysisView.viewers).some((v) => v.type === VIEWER_TYPE.DENDROGRAM);
114
114
  const dendrogram = ui.boolInput(VIEWER_TYPE.DENDROGRAM, isDendrogramEnabled ?? false,
115
115
  () => result.showDendrogram = dendrogram.value) as DG.InputBase<boolean>;
116
+ const clusterMaxActivity = ui.boolInput(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, !!settings?.showClusterMaxActivity, () => {
117
+ result.showClusterMaxActivity = clusterMaxActivity.value ?? undefined;
118
+ });
116
119
  const showSeqSpace = ui.boolInput('Sequence space', !!settings?.showSequenceSpace, () => {
117
120
  result.showSequenceSpace = showSeqSpace.value ?? undefined;
118
121
  if (showSeqSpace.value) {
@@ -126,11 +129,12 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
126
129
  if (result.showSequenceSpace === settings?.showSequenceSpace)
127
130
  delete result.showSequenceSpace;
128
131
  });
132
+ clusterMaxActivity.setTooltip('Show cluster max activity viewer');
129
133
  dendrogram.setTooltip('Show dendrogram viewer');
130
134
  dendrogram.enabled = getTreeHelperInstance() !== null;
131
135
 
132
- accordion.addPane(SETTINGS_PANES.VIEWERS, () => ui.inputs([dendrogram, showSeqSpace]), true);
133
- inputs[SETTINGS_PANES.VIEWERS] = [dendrogram];
136
+ accordion.addPane(SETTINGS_PANES.VIEWERS, () => ui.inputs([dendrogram, showSeqSpace, clusterMaxActivity]), true);
137
+ inputs[SETTINGS_PANES.VIEWERS] = [dendrogram, showSeqSpace, clusterMaxActivity];
134
138
 
135
139
  // Columns to include pane options
136
140
  const inputsRows: HTMLElement[] = [];