@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
3
  "friendlyName": "Peptides",
4
- "version": "1.17.14",
4
+ "version": "1.17.16",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
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 = '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: Cluster Max Activity
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 maxActivityInClusterSizeColName = '~max.activity.for.cluster.size' as const;
34
- private scFilterQuery = `\$\{${ClusterMaxActivityViewer.maxActivityInClusterSizeColName}\} == 1` as const;
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
- // 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
- // });
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 maxActivityIndexPerClusterSizeMap: {[key: number]: number} = {};
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 clusterSize: number | null = clusterSizeCol.get(i);
120
- if (clusterSize == null || clusterSizeCol.isNone(i) || activityCol.isNone(i))
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 = maxActivityIndexPerClusterSizeMap[clusterSize];
135
+ const prevMaxActivityIndex = maxActivityIndexPerClusterMap[cluster];
124
136
  if (prevMaxActivityIndex == null || prevMaxActivityIndex == undefined)
125
- maxActivityIndexPerClusterSizeMap[clusterSize] = i;
137
+ maxActivityIndexPerClusterMap[cluster] = i;
126
138
  else {
127
139
  if (activity > activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.HIGH)
128
- maxActivityIndexPerClusterSizeMap[clusterSize] = i;
140
+ maxActivityIndexPerClusterMap[cluster] = i;
129
141
  else if (activity < activityCol.get(prevMaxActivityIndex) && this.activityTarget === ACTIVITY_TARGET.LOW)
130
- maxActivityIndexPerClusterSizeMap[clusterSize] = i;
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.maxActivityInClusterSizeColName, DG.COLUMN_TYPE.INT, this.dataFrame.rowCount);
157
+ ClusterMaxActivityViewer.maxActivityInClusterColName, DG.COLUMN_TYPE.INT, this.dataFrame.rowCount);
136
158
  maxAtivityInClusterSizeCol.init((i) => {
137
- if (clusterSizeCol.isNone(i))
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 === maxActivityIndexPerClusterSizeMap[clusterSizeCol.get(i)] ? 1 : 0;
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
@@ -2,6 +2,9 @@ const path = require('path');
2
2
  const packageName = path.parse(require('./package.json').name).name.toLowerCase().replace(/-/g, '');
3
3
 
4
4
  module.exports = {
5
+ cache: {
6
+ type: 'filesystem',
7
+ },
5
8
  mode: 'development',
6
9
  entry: {
7
10
  package: ['./src/package.ts'],