@datagrok/peptides 1.17.14 → 1.17.16
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 +8 -0
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +1 -1
- package/src/model.ts +4 -1
- package/src/package.ts +1 -1
- package/src/viewers/cluster-max-activity-viewer.ts +156 -30
- package/webpack.config.js +3 -0
package/package.json
CHANGED
package/src/model.ts
CHANGED
|
@@ -60,7 +60,7 @@ export enum VIEWER_TYPE {
|
|
|
60
60
|
MOST_POTENT_RESIDUES = 'Most Potent Residues',
|
|
61
61
|
LOGO_SUMMARY_TABLE = 'Logo Summary Table',
|
|
62
62
|
DENDROGRAM = 'Dendrogram',
|
|
63
|
-
CLUSTER_MAX_ACTIVITY = '
|
|
63
|
+
CLUSTER_MAX_ACTIVITY = 'Active peptide selection',
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export type CachedWebLogoTooltip = { bar: string, tooltip: HTMLDivElement | null };
|
|
@@ -1132,6 +1132,9 @@ export class PeptidesModel {
|
|
|
1132
1132
|
activityColumnName: this.settings!.activityColumnName,
|
|
1133
1133
|
clusterColumnName: potentialClusterCol ?? wu(this.df.columns.categorical).next().value?.name,
|
|
1134
1134
|
activityTarget: C.ACTIVITY_TARGET.HIGH,
|
|
1135
|
+
connectivityColumnName: this._mclCols.find((colName) => colName.toLowerCase().startsWith('connectivity')),
|
|
1136
|
+
clusterSizeThreshold: 20,
|
|
1137
|
+
activityThreshold: 1000,
|
|
1135
1138
|
};
|
|
1136
1139
|
const _clusterMaxActivity = await this.df.plot
|
|
1137
1140
|
.fromType(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, viewerProperties) as ClusterMaxActivityViewer;
|
package/src/package.ts
CHANGED
|
@@ -130,7 +130,7 @@ export function logoSummaryTable(): LogoSummaryTable {
|
|
|
130
130
|
return new LogoSummaryTable();
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
//name:
|
|
133
|
+
//name: Active peptide selection
|
|
134
134
|
//tags: viewer
|
|
135
135
|
//output: viewer result
|
|
136
136
|
export function clusterMaxActivity(): ClusterMaxActivityViewer {
|
|
@@ -5,33 +5,51 @@ import {Options} from '@datagrok-libraries/utils/src/type-declarations';
|
|
|
5
5
|
import {ACTIVITY_TARGET, COLUMN_NAME, COLUMNS_NAMES} from '../utils/constants';
|
|
6
6
|
import wu from 'wu';
|
|
7
7
|
import $ from 'cash-dom';
|
|
8
|
+
import * as rxjs from 'rxjs';
|
|
9
|
+
import {filter} from 'rxjs/operators';
|
|
8
10
|
export const enum ClusterMaxActivityProps {
|
|
9
11
|
CLUSTER_COLUMN = 'cluster',
|
|
10
12
|
ACTIVITY_COLUMN = 'activity',
|
|
13
|
+
CONNECTIVITY_COLUMN = 'connectivity',
|
|
11
14
|
COLOR_COLUMN = 'color',
|
|
15
|
+
CLUSTER_SIZE_THRESHOLD = 'clusterSizeThreshold',
|
|
16
|
+
ACTIVITY_THRESHOLD = 'activityThreshold',
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
export interface IClusterMaxActivity {
|
|
15
20
|
clusterColumnName: string;
|
|
16
21
|
activityColumnName: string;
|
|
22
|
+
connectivityColumnName?: string;
|
|
17
23
|
colorColumnName?: string;
|
|
18
24
|
activityTarget: ACTIVITY_TARGET;
|
|
25
|
+
clusterSizeThreshold: number;
|
|
26
|
+
activityThreshold: number;
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
|
|
22
30
|
export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMaxActivity {
|
|
23
|
-
_titleHost = ui.divText(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, {id: 'pep-viewer-title'});
|
|
31
|
+
_titleHost = ui.divText(VIEWER_TYPE.CLUSTER_MAX_ACTIVITY, {id: 'pep-viewer-title', style: {marginRight: 'auto'}});
|
|
32
|
+
_selsectIcon: HTMLElement = ui.div();
|
|
24
33
|
clusterColumnName: string;
|
|
25
34
|
activityColumnName: string;
|
|
26
35
|
colorColumnName: string;
|
|
36
|
+
connectivityColumnName?: string | undefined;
|
|
27
37
|
activityTarget: ACTIVITY_TARGET = ACTIVITY_TARGET.HIGH;
|
|
28
38
|
_scViewer?: DG.ScatterPlotViewer | null;
|
|
29
39
|
viewerError: string = '';
|
|
30
40
|
renderTimeout: NodeJS.Timeout | number | null = null;
|
|
31
41
|
renderDebounceTime = 500;
|
|
42
|
+
clusterSizeThreshold: number;
|
|
43
|
+
activityThreshold: number;
|
|
32
44
|
static clusterSizeColName = '~cluster.size' as const;
|
|
33
|
-
static
|
|
34
|
-
|
|
45
|
+
static maxActivityInClusterColName = '~max.activity.for.cluster' as const;
|
|
46
|
+
static maxConnectivityInClusterColName = '~max.connectivity.for.cluster' as const;
|
|
47
|
+
static synSelectionColName = 'Syn Selection' as const;
|
|
48
|
+
static maxActivityLabel = 'Max Activity' as const;
|
|
49
|
+
static maxConnectivityLabel = 'Max Connectivity' as const;
|
|
50
|
+
private scFilterQuery = `\$\{${ClusterMaxActivityViewer.maxActivityInClusterColName}\} == 1` as const;
|
|
51
|
+
private selectionSubscription: rxjs.Subscription | null = null;
|
|
52
|
+
private linesDrawSubscription: rxjs.Subscription | null = null;
|
|
35
53
|
get scViewer(): DG.ScatterPlotViewer | null {
|
|
36
54
|
if (!this._scViewer)
|
|
37
55
|
this._scViewer = this.createSCViewer();
|
|
@@ -46,6 +64,9 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
46
64
|
this.activityTarget = this.string(
|
|
47
65
|
'activityTarget', ACTIVITY_TARGET.HIGH, {choices: [ACTIVITY_TARGET.HIGH, ACTIVITY_TARGET.LOW]},
|
|
48
66
|
) as ACTIVITY_TARGET;
|
|
67
|
+
this.clusterSizeThreshold = this.int(ClusterMaxActivityProps.CLUSTER_SIZE_THRESHOLD, 20);
|
|
68
|
+
this.activityThreshold = this.int(ClusterMaxActivityProps.ACTIVITY_THRESHOLD, 1000);
|
|
69
|
+
this.connectivityColumnName = this.column(ClusterMaxActivityProps.CONNECTIVITY_COLUMN, {nullable: true});
|
|
49
70
|
}
|
|
50
71
|
|
|
51
72
|
/**
|
|
@@ -80,6 +101,8 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
80
101
|
}
|
|
81
102
|
const activityCol = this.dataFrame.columns.byName(this.activityColumnName);
|
|
82
103
|
const clusterCol = this.dataFrame.columns.byName(this.clusterColumnName);
|
|
104
|
+
const connectivityCol = this.connectivityColumnName != null ?
|
|
105
|
+
this.dataFrame.columns.byName(this.connectivityColumnName) : null;
|
|
83
106
|
const numericColTypes: DG.ColumnType[] =
|
|
84
107
|
[DG.COLUMN_TYPE.FLOAT, DG.COLUMN_TYPE.INT, DG.COLUMN_TYPE.BIG_INT, DG.COLUMN_TYPE.QNUM];
|
|
85
108
|
if (!numericColTypes.includes(activityCol.type)) {
|
|
@@ -95,55 +118,155 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
95
118
|
continue;
|
|
96
119
|
clusterSizeMap[cluster] = (clusterSizeMap[cluster] ?? 0) + 1;
|
|
97
120
|
}
|
|
98
|
-
|
|
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
|
-
// });
|
|
121
|
+
|
|
110
122
|
clusterSizeCol.init((i) => clusterCol.isNone(i) ? null : clusterSizeMap[clusterCol.get(i)] ?? null);
|
|
111
123
|
|
|
112
124
|
if (activityCol.stats.min <= 0)
|
|
113
125
|
scatterPlotProps.yAxisType = 'linear';
|
|
114
126
|
|
|
115
127
|
// create a new column to store max activity for each cluster size
|
|
116
|
-
const
|
|
117
|
-
|
|
128
|
+
const maxActivityIndexPerClusterMap: {[key: number]: number} = {};
|
|
129
|
+
const maxConnectivityIndexPerClusterMap: {[key: number]: number} = {};
|
|
118
130
|
for (let i = 0; i < this.dataFrame.rowCount; i++) {
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
131
|
+
const cluster: number | null = clusterCol.get(i);
|
|
132
|
+
if (cluster == null || clusterCol.isNone(i) || activityCol.isNone(i))
|
|
121
133
|
continue;
|
|
122
134
|
const activity: number = activityCol.get(i);
|
|
123
|
-
const prevMaxActivityIndex =
|
|
135
|
+
const prevMaxActivityIndex = maxActivityIndexPerClusterMap[cluster];
|
|
124
136
|
if (prevMaxActivityIndex == null || prevMaxActivityIndex == undefined)
|
|
125
|
-
|
|
137
|
+
maxActivityIndexPerClusterMap[cluster] = i;
|
|
126
138
|
else {
|
|
127
139
|
if (activity > activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.HIGH)
|
|
128
|
-
|
|
140
|
+
maxActivityIndexPerClusterMap[cluster] = i;
|
|
129
141
|
else if (activity < activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.LOW)
|
|
130
|
-
|
|
142
|
+
maxActivityIndexPerClusterMap[cluster] = i;
|
|
143
|
+
}
|
|
144
|
+
if (connectivityCol) {
|
|
145
|
+
const connectivity: number = connectivityCol.get(i);
|
|
146
|
+
const prevMaxConnectivityIndex = maxConnectivityIndexPerClusterMap[cluster];
|
|
147
|
+
if (prevMaxConnectivityIndex == null || prevMaxConnectivityIndex == undefined)
|
|
148
|
+
maxConnectivityIndexPerClusterMap[cluster] = i;
|
|
149
|
+
else {
|
|
150
|
+
if (connectivity > connectivityCol.get(prevMaxConnectivityIndex))
|
|
151
|
+
maxConnectivityIndexPerClusterMap[cluster] = i;
|
|
152
|
+
}
|
|
131
153
|
}
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
const maxAtivityInClusterSizeCol = this.dataFrame.columns.getOrCreate(
|
|
135
|
-
ClusterMaxActivityViewer.
|
|
157
|
+
ClusterMaxActivityViewer.maxActivityInClusterColName, DG.COLUMN_TYPE.INT, this.dataFrame.rowCount);
|
|
136
158
|
maxAtivityInClusterSizeCol.init((i) => {
|
|
137
|
-
if (
|
|
159
|
+
if (clusterCol.isNone(i))
|
|
160
|
+
return 0;
|
|
161
|
+
return i === maxActivityIndexPerClusterMap[clusterCol.get(i)] ? 1 : 0;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const maxConnectivityInClusterSizeCol = this.dataFrame.columns.getOrCreate(
|
|
165
|
+
ClusterMaxActivityViewer.maxConnectivityInClusterColName, DG.COLUMN_TYPE.INT, this.dataFrame.rowCount);
|
|
166
|
+
maxConnectivityInClusterSizeCol.init((i) => {
|
|
167
|
+
if (clusterCol.isNone(i))
|
|
138
168
|
return 0;
|
|
139
|
-
return i ===
|
|
169
|
+
return i === maxConnectivityIndexPerClusterMap[clusterCol.get(i)] ? 1 : 0;
|
|
140
170
|
});
|
|
171
|
+
|
|
172
|
+
const synSelectionCol = this.dataFrame.columns.getOrCreate(
|
|
173
|
+
ClusterMaxActivityViewer.synSelectionColName, DG.TYPE.STRING, this.dataFrame.rowCount);
|
|
174
|
+
|
|
175
|
+
synSelectionCol.init((i) => {
|
|
176
|
+
if (clusterCol.isNone(i))
|
|
177
|
+
return null;
|
|
178
|
+
if (i === maxActivityIndexPerClusterMap[clusterCol.get(i)])
|
|
179
|
+
return ClusterMaxActivityViewer.maxActivityLabel;
|
|
180
|
+
if (connectivityCol && i === maxConnectivityIndexPerClusterMap[clusterCol.get(i)])
|
|
181
|
+
return ClusterMaxActivityViewer.maxConnectivityLabel;
|
|
182
|
+
return null;
|
|
183
|
+
});
|
|
184
|
+
|
|
141
185
|
scatterPlotProps.xColumnName = ClusterMaxActivityViewer.clusterSizeColName;
|
|
142
186
|
scatterPlotProps.yColumnName = this.activityColumnName;
|
|
143
187
|
scatterPlotProps.filter = this.scFilterQuery;
|
|
144
188
|
this.viewerError = '';
|
|
145
189
|
const sc = DG.Viewer.scatterPlot(this.dataFrame, scatterPlotProps);
|
|
146
190
|
|
|
191
|
+
if (this.selectionSubscription)
|
|
192
|
+
this.selectionSubscription.unsubscribe();
|
|
193
|
+
this.selectionSubscription = sc.onDataEvent.pipe(filter((e) => e.type == 'd4-select')).subscribe((e) => {
|
|
194
|
+
const indexes = e.bitset?.getSelectedIndexes() ?? [];
|
|
195
|
+
const currentSelection = this.dataFrame.selection;
|
|
196
|
+
const filterBitset = DG.BitSet.create(this.dataFrame.rowCount, (i) => maxAtivityInClusterSizeCol.get(i) == 1);
|
|
197
|
+
filterBitset.and(currentSelection);
|
|
198
|
+
for (let i = 0; i < indexes.length; i++) {
|
|
199
|
+
const index = indexes[i];
|
|
200
|
+
const cluster = clusterCol.get(index);
|
|
201
|
+
if (clusterCol.isNone(index))
|
|
202
|
+
continue;
|
|
203
|
+
filterBitset.set(index, true);
|
|
204
|
+
if (maxConnectivityIndexPerClusterMap[cluster] != null)
|
|
205
|
+
filterBitset.set(maxConnectivityIndexPerClusterMap[cluster], true);
|
|
206
|
+
}
|
|
207
|
+
filterBitset.fireChanged();
|
|
208
|
+
const filteredIndexes = filterBitset.getSelectedIndexes();
|
|
209
|
+
for (const i of filteredIndexes) {
|
|
210
|
+
const cluster = clusterCol.get(i);
|
|
211
|
+
if (cluster == null)
|
|
212
|
+
continue;
|
|
213
|
+
if (maxConnectivityIndexPerClusterMap[cluster] != null)
|
|
214
|
+
filterBitset.set(maxConnectivityIndexPerClusterMap[cluster], true);
|
|
215
|
+
}
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
this.dataFrame.selection.copyFrom(filterBitset, true);
|
|
218
|
+
setTimeout(() => {
|
|
219
|
+
if (this.model)
|
|
220
|
+
this.model.createAccordion();
|
|
221
|
+
}, 200);
|
|
222
|
+
}, 200);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const selectTopQuadrants = (): void => {
|
|
226
|
+
const selectionBitset = DG.BitSet.create(this.dataFrame.rowCount);
|
|
227
|
+
Object.entries(maxActivityIndexPerClusterMap).forEach(([cluster, index]) => {
|
|
228
|
+
if (cluster == null || index == null)
|
|
229
|
+
return;
|
|
230
|
+
const clusterInt = parseInt(cluster);
|
|
231
|
+
const activity = activityCol.get(index);
|
|
232
|
+
const clusterSize = clusterSizeMap[clusterInt] ?? clusterSizeMap[cluster];
|
|
233
|
+
if (activity < this.activityThreshold && clusterSize < this.clusterSizeThreshold)
|
|
234
|
+
return;
|
|
235
|
+
selectionBitset.set(index, true, false);
|
|
236
|
+
if (maxConnectivityIndexPerClusterMap[clusterInt] != null)
|
|
237
|
+
selectionBitset.set(maxConnectivityIndexPerClusterMap[clusterInt], true, false);
|
|
238
|
+
});
|
|
239
|
+
selectionBitset.fireChanged();
|
|
240
|
+
this.dataFrame.selection.copyFrom(selectionBitset, true);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
this._selsectIcon = ui.iconSvg('select-all', () => {
|
|
244
|
+
selectTopQuadrants();
|
|
245
|
+
}, 'Select 3 Active quadrants');
|
|
246
|
+
this._selsectIcon.style.cursor = 'pointer';
|
|
247
|
+
this._selsectIcon.style.marginRight = '5px';
|
|
248
|
+
selectTopQuadrants();
|
|
249
|
+
if (this.linesDrawSubscription)
|
|
250
|
+
this.linesDrawSubscription.unsubscribe();
|
|
251
|
+
this.linesDrawSubscription = sc.onBeforeDrawScene.subscribe(() => {
|
|
252
|
+
const canvas = sc.getInfo().canvas;
|
|
253
|
+
const ctx: CanvasRenderingContext2D = canvas.getContext('2d');
|
|
254
|
+
const viewPort = sc.viewport;
|
|
255
|
+
const startPointHor = sc.worldToScreen(viewPort.x, this.activityThreshold);
|
|
256
|
+
const startPointVer = sc.worldToScreen(this.clusterSizeThreshold, viewPort.y);
|
|
257
|
+
const endPointHor = sc.worldToScreen(viewPort.x + viewPort.width, this.activityThreshold);
|
|
258
|
+
const endPointVer = sc.worldToScreen(this.clusterSizeThreshold, viewPort.y + viewPort.height);
|
|
259
|
+
ctx.beginPath();
|
|
260
|
+
ctx.strokeStyle = 'rgb(0,0,0)';
|
|
261
|
+
ctx.lineWidth = 1;
|
|
262
|
+
ctx.moveTo(startPointHor.x, startPointHor.y);
|
|
263
|
+
ctx.lineTo(endPointHor.x, endPointHor.y);
|
|
264
|
+
ctx.moveTo(startPointVer.x, startPointVer.y);
|
|
265
|
+
ctx.lineTo(endPointVer.x, endPointVer.y);
|
|
266
|
+
ctx.stroke();
|
|
267
|
+
ctx.closePath();
|
|
268
|
+
});
|
|
269
|
+
|
|
147
270
|
return sc;
|
|
148
271
|
}
|
|
149
272
|
|
|
@@ -158,12 +281,13 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
158
281
|
if (clusterCol != null)
|
|
159
282
|
this.getProperty(`${ClusterMaxActivityProps.CLUSTER_COLUMN}${COLUMN_NAME}`)?.set(this, clusterCol.name);
|
|
160
283
|
|
|
284
|
+
const connectivityCol: DG.Column | null = wu(this.dataFrame?.columns.numerical).next()?.value;
|
|
285
|
+
if (connectivityCol != null)
|
|
286
|
+
this.getProperty(`${ClusterMaxActivityProps.CONNECTIVITY_COLUMN}${COLUMN_NAME}`)?.set(this, connectivityCol.name);
|
|
287
|
+
|
|
161
288
|
this.render();
|
|
162
289
|
|
|
163
290
|
this.dataFrame.onDataChanged.subscribe(() => {
|
|
164
|
-
// this._scViewer = null;
|
|
165
|
-
// this.render();
|
|
166
|
-
|
|
167
291
|
this.render();
|
|
168
292
|
});
|
|
169
293
|
}
|
|
@@ -193,14 +317,16 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
193
317
|
marginLeft: '5px',
|
|
194
318
|
}});
|
|
195
319
|
scViewer.props.colorColumnName = this.colorColumnName ?? null;
|
|
320
|
+
|
|
196
321
|
this.root.appendChild(
|
|
197
322
|
ui.divH([
|
|
198
323
|
maxActivityLabel,
|
|
199
324
|
ui.divV([
|
|
200
|
-
ui.divH([this._titleHost], {
|
|
325
|
+
ui.divH([this._titleHost, this._selsectIcon], {
|
|
201
326
|
style: {
|
|
202
327
|
alignSelf: 'center',
|
|
203
328
|
lineHeight: 'normal',
|
|
329
|
+
width: '100%',
|
|
204
330
|
},
|
|
205
331
|
}),
|
|
206
332
|
scViewer.root,
|
package/webpack.config.js
CHANGED