@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/CHANGELOG.md +20 -4
- package/dist/301.js +2 -2
- package/dist/997.js +2 -2
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +8 -8
- package/src/model.ts +34 -9
- package/src/package.ts +8 -0
- package/src/utils/types.ts +1 -0
- package/src/viewers/cluster-max-activity-viewer.ts +228 -0
- package/src/viewers/logo-summary.ts +1 -1
- package/src/widgets/manual-alignment.ts +4 -5
- package/src/widgets/settings.ts +6 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
3
|
"friendlyName": "Peptides",
|
|
4
|
-
"version": "1.17.
|
|
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.
|
|
17
|
-
"@datagrok-libraries/ml": "^6.4.
|
|
18
|
-
"@datagrok-libraries/statistics": "^1.2.
|
|
19
|
-
"@datagrok-libraries/utils": "^4.1.
|
|
20
|
-
"@datagrok-libraries/tutorials": "^1.3.
|
|
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 {
|
|
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 =
|
|
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
|
|
1297
|
-
const 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 =
|
|
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}
|
package/src/utils/types.ts
CHANGED
|
@@ -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
|
|
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 {
|
|
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
|
|
21
|
+
const sh = SeqHandler.forColumn(alignedSequenceCol);
|
|
22
22
|
const newSequence = sequenceInput.value;
|
|
23
|
-
const
|
|
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
|
|
27
|
+
const part = splitSequence.getCanonical(i);
|
|
29
28
|
if (currentDf.col(i.toString()) !== null)
|
|
30
29
|
currentDf.set(i.toString(), affectedRowIndex, part);
|
|
31
30
|
}
|
package/src/widgets/settings.ts
CHANGED
|
@@ -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[] = [];
|