@datagrok/peptides 0.8.6 → 0.8.7

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.
@@ -5,6 +5,17 @@ import {PeptideSimilaritySpaceWidget, createPeptideSimilaritySpaceViewer} from '
5
5
  import {
6
6
  createDimensinalityReducingWorker,
7
7
  } from '@datagrok-libraries/ml/src/workers/dimensionality-reducing-worker-creator';
8
+ import {runKalign} from '../utils/multiple-sequence-alignment';
9
+ import { StringMetrics } from '@datagrok-libraries/ml/src/typed-metrics';
10
+
11
+ /**
12
+ * Tests if a table has non zero rows and columns.
13
+ *
14
+ * @param {DG.DataFrame} table Target table.
15
+ */
16
+ export function _testTableIsNotEmpty(table: DG.DataFrame) {
17
+ expect(table.columns.length > 0 && table.rowCount > 0, true);
18
+ }
8
19
 
9
20
  /**
10
21
  * Tests if peptide space viewer is drawing without exceptions.
@@ -31,9 +42,18 @@ export async function _testViewerIsDrawing(table: DG.DataFrame, view: DG.TableVi
31
42
  * @param {string} method Embedding method.
32
43
  * @param {string} measure Measure to apply to a pair of strings.
33
44
  */
34
- export async function _testDimensionalityReducer(columnData: Array<string>, method: string, measure: string) {
45
+ export async function _testDimensionalityReducer(columnData: Array<string>, method: StringMetrics, measure: string) {
46
+ let noException = true;
35
47
  const cyclesCount = 100;
36
- const embcols = await createDimensinalityReducingWorker(columnData, method, measure, cyclesCount);
48
+ let embcols;
49
+
50
+ try {
51
+ embcols = await createDimensinalityReducingWorker({data: columnData, metric: measure as StringMetrics}, method, cyclesCount);
52
+ } catch (error) {
53
+ noException = false;
54
+ }
55
+ expect(noException, true);
56
+
37
57
  const [X, Y] = embcols as Array<Float32Array>;
38
58
 
39
59
  expect(X.every((v) => v !== null && v !== NaN), true);
@@ -58,20 +78,28 @@ export async function _testPeptideSimilaritySpaceViewer(
58
78
  method: string,
59
79
  measure: string,
60
80
  cyclesCount: number,
61
- //view: DG.TableView | null,
62
- //activityColumnName?: string | null,
63
81
  ) {
64
- const viewer = await createPeptideSimilaritySpaceViewer(
65
- table,
66
- alignedSequencesColumn,
67
- method,
68
- measure,
69
- cyclesCount,
70
- null, // view,
71
- // activityColumnName,
72
- );
73
- const df = viewer.dataFrame;
74
82
  let noException = true;
83
+ let viewer;
84
+ let df: DG.DataFrame;
85
+
86
+ try {
87
+ viewer = await createPeptideSimilaritySpaceViewer(
88
+ table,
89
+ alignedSequencesColumn,
90
+ method,
91
+ measure,
92
+ cyclesCount,
93
+ null,
94
+ );
95
+ df = viewer.dataFrame!;
96
+ } catch (error) {
97
+ noException = false;
98
+ }
99
+
100
+ expect(noException, true);
101
+
102
+ noException = true;
75
103
 
76
104
  try {
77
105
  const axesNames = ['~X', '~Y', '~MW'];
@@ -84,3 +112,15 @@ export async function _testPeptideSimilaritySpaceViewer(
84
112
  }
85
113
  expect(noException, true);
86
114
  }
115
+
116
+ /**
117
+ * Tests if MSA works and returns consistent result.
118
+ *
119
+ * @export
120
+ * @param {DG.Column} col Aligned sequences column.
121
+ */
122
+ export async function _testMSAIsCorrect(col: DG.Column) {
123
+ const msaCol = await runKalign(col, true);
124
+ expect(msaCol.toList().every((v, i) => v == col.get(i)), true);
125
+ }
126
+
@@ -301,3 +301,105 @@ export function processSequence(subParts: string[]): [string[], boolean] {
301
301
  });
302
302
  return [text, simplified];
303
303
  }
304
+
305
+ /**
306
+ * Aligned sequence difference cell renderer.
307
+ *
308
+ * @export
309
+ * @class AlignedSequenceDifferenceCellRenderer
310
+ * @extends {DG.GridCellRenderer}
311
+ */
312
+ export class AlignedSequenceDifferenceCellRenderer extends DG.GridCellRenderer {
313
+ /**
314
+ * Renderer name.
315
+ *
316
+ * @readonly
317
+ * @memberof AlignedSequenceDifferenceCellRenderer
318
+ */
319
+ get name() {
320
+ return 'alignedSequenceDifferenceCR';
321
+ }
322
+
323
+ /**
324
+ * Cell type.
325
+ *
326
+ * @readonly
327
+ * @memberof AlignedSequenceDifferenceCellRenderer
328
+ */
329
+ get cellType() {
330
+ return 'alignedSequenceDifference';
331
+ }
332
+
333
+ /**
334
+ * Cell height.
335
+ *
336
+ * @readonly
337
+ * @memberof AlignedSequenceDifferenceCellRenderer
338
+ */
339
+ get defaultHeight() {
340
+ return 35;
341
+ }
342
+
343
+ /**
344
+ * Cell renderer function.
345
+ *
346
+ * @param {CanvasRenderingContext2D} g Canvas rendering context.
347
+ * @param {number} x x coordinate on the canvas.
348
+ * @param {number} y y coordinate on the canvas.
349
+ * @param {number} w width of the cell.
350
+ * @param {number} h height of the cell.
351
+ * @param {DG.GridCell} gridCell Grid cell.
352
+ * @param {DG.GridCellStyle} cellStyle Cell style.
353
+ * @memberof AlignedSequenceDifferenceCellRenderer
354
+ */
355
+ render(
356
+ g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
357
+ gridCell: DG.GridCell, cellStyle: DG.GridCellStyle,
358
+ ) {
359
+ const grid = gridCell.dart.grid ? gridCell.grid : gridCell.dart.grid;
360
+ const cell = gridCell.cell;
361
+
362
+ w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
363
+ y += 3;
364
+ g.save();
365
+ g.beginPath();
366
+ g.rect(x, y, w, h);
367
+ g.clip();
368
+ g.font = '14px monospace';
369
+ g.textBaseline = 'top';
370
+ const s: string = cell.value ?? '';
371
+
372
+ //TODO: can this be replaced/merged with splitSequence?
373
+ const [s1, s2] = s.split('#');
374
+ const subParts1 = s1.split('-');
375
+ const subParts2 = s2.split('-');
376
+ const [text, simplified] = processSequence(subParts1);
377
+ const textSize = g.measureText(text.join(''));
378
+ x = Math.max(x, x + (w - textSize.width) / 2);
379
+
380
+ subParts1.forEach((amino1: string, index) => {
381
+ let color, pivot;
382
+ let amino2 = subParts2[index];
383
+
384
+ if (amino1 != '')
385
+ [color, pivot] = cp.getColorPivot(amino1);
386
+ else
387
+ [color, pivot] = cp.getColorPivot(amino2);
388
+
389
+ if (amino1 != amino2) {
390
+ const verticalShift = 10;
391
+
392
+ if (amino1 == '')
393
+ amino1 = '-';
394
+ if (amino2 == '')
395
+ amino2 = '-';
396
+
397
+ printLeftOrCentered(x, y - verticalShift, w, h, g, amino1, 'red', pivot, true);
398
+ x = printLeftOrCentered(x, y + verticalShift, w, h, g, amino2, 'red', pivot, true);
399
+ } else {
400
+ x = printLeftOrCentered(x, y, w, h, g, amino1, color, pivot, true);
401
+ }
402
+ });
403
+ g.restore();
404
+ }
405
+ }
@@ -2,6 +2,8 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
+ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
+
5
7
  /**
6
8
  * Chem palette class.
7
9
  *
@@ -9,7 +11,7 @@ import * as DG from 'datagrok-api/dg';
9
11
  * @class ChemPalette
10
12
  */
11
13
  export class ChemPalette {
12
- cp: {[key: string]: string} = {};
14
+ cp: StringDictionary = {};
13
15
 
14
16
  /**
15
17
  * Creates an instance of ChemPalette.
@@ -213,10 +215,10 @@ export class ChemPalette {
213
215
  * Amino acid residue names.
214
216
  *
215
217
  * @static
216
- * @type {{[key: string]: string}}
218
+ * @type {StringDictionary}
217
219
  * @memberof ChemPalette
218
220
  */
219
- static AANames: {[key: string]: string} = {
221
+ static AANames: StringDictionary = {
220
222
  'G': 'Glycine',
221
223
  'L': 'Leucine',
222
224
  'Y': 'Tyrosine',
@@ -243,10 +245,10 @@ export class ChemPalette {
243
245
  * Amino acid residue SMILES.
244
246
  *
245
247
  * @static
246
- * @type {{[key: string]: string}}
248
+ * @type {StringDictionary}
247
249
  * @memberof ChemPalette
248
250
  */
249
- static AASmiles: {[key: string]: string} = {
251
+ static AASmiles: StringDictionary = {
250
252
  'G': 'NCC(=O)O',
251
253
  'L': 'N[C@H](CC(C)C)C(=O)O',
252
254
  'Y': 'NC(CC1=CC=C(O)C=C1)C(=O)O',
@@ -273,10 +275,10 @@ export class ChemPalette {
273
275
  * Amino acid residue truncated SMILES.
274
276
  *
275
277
  * @static
276
- * @type {{[key: string]: string}}
278
+ * @type {StringDictionary}
277
279
  * @memberof ChemPalette
278
280
  */
279
- static AASmilesTruncated: {[key: string]: string} = {
281
+ static AASmilesTruncated: StringDictionary = {
280
282
  'G': '*C*',
281
283
  'L': 'CC(C)C[C@H](*)*',
282
284
  'Y': 'C1=CC(=CC=C1CC(*)*)O',
@@ -303,10 +305,10 @@ export class ChemPalette {
303
305
  * Amino acid residue full names.
304
306
  *
305
307
  * @static
306
- * @type {{[key: string]: string}}
308
+ * @type {StringDictionary}
307
309
  * @memberof ChemPalette
308
310
  */
309
- static AAFullNames: {[key: string]: string} = {
311
+ static AAFullNames: StringDictionary = {
310
312
  'Ala': 'A',
311
313
  'Arg': 'R',
312
314
  'Asn': 'N',
@@ -72,7 +72,6 @@ export async function runKalign(col: DG.Column, isAligned = false) : Promise<DG.
72
72
  if (isAligned)
73
73
  sequences = sequences.map((v: string, _) => AlignedSequenceEncoder.clean(v).replace(/\-/g, ''));
74
74
 
75
-
76
75
  const fasta = _stringsToFasta(sequences);
77
76
 
78
77
  const CLI = await new Aioli('kalign/3.3.1');
@@ -8,7 +8,7 @@ import {DimensionalityReducer} from '@datagrok-libraries/ml/src/reduce-dimension
8
8
  import {
9
9
  createDimensinalityReducingWorker,
10
10
  } from '@datagrok-libraries/ml/src/workers/dimensionality-reducing-worker-creator';
11
- import {StringMeasure} from '@datagrok-libraries/ml/src/string-measure';
11
+ import {Measure, StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
12
12
  import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
13
13
 
14
14
  /**
@@ -67,7 +67,7 @@ export async function createPeptideSimilaritySpaceViewer(
67
67
  const axesNames = ['~X', '~Y', '~MW'];
68
68
  const columnData = alignedSequencesColumn.toList().map((v, _) => AlignedSequenceEncoder.clean(v));
69
69
 
70
- const embcols = await createDimensinalityReducingWorker(columnData, method, measure, cyclesCount);
70
+ const embcols = await createDimensinalityReducingWorker({data: columnData, metric: measure as StringMetrics}, method, cyclesCount);
71
71
 
72
72
  const columns = Array.from(
73
73
  embcols as Coordinates,
@@ -109,7 +109,6 @@ export async function createPeptideSimilaritySpaceViewer(
109
109
  if (view !== null)
110
110
  view.addViewer(viewer);
111
111
 
112
-
113
112
  pi.close();
114
113
  return viewer;
115
114
  }
@@ -139,7 +138,7 @@ export class PeptideSimilaritySpaceWidget {
139
138
  */
140
139
  constructor(alignedSequencesColumn: DG.Column, view: DG.TableView) {
141
140
  this.availableMethods = DimensionalityReducer.availableMethods;
142
- this.availableMetrics = StringMeasure.availableMeasures;
141
+ this.availableMetrics = Measure.getMetricByDataType('String');
143
142
  this.method = this.availableMethods[0];
144
143
  this.metrics = this.availableMetrics[0];
145
144
  this.currentDf = alignedSequencesColumn.dataFrame;
@@ -175,9 +174,10 @@ export class PeptideSimilaritySpaceWidget {
175
174
  * @memberof PeptideSimilaritySpaceWidget
176
175
  */
177
176
  protected async updateViewer() {
178
- this.viewer.lastChild?.remove();
179
177
  const viewer = await this.drawViewer();
178
+ this.viewer.lastChild?.remove();
180
179
  this.viewer.appendChild(viewer.root);
180
+ viewer.dataFrame?.fireValuesChanged();
181
181
  }
182
182
 
183
183
  /**
@@ -222,6 +222,25 @@ export class PeptideSimilaritySpaceWidget {
222
222
  * @memberof PeptideSimilaritySpaceWidget
223
223
  */
224
224
  public async draw(): Promise<DG.Widget> {
225
- return new DG.Widget(ui.divV([(await this.drawViewer()).root, await this.drawInputs()]));
225
+ const plot = await this.drawViewer();
226
+ const inputs = await this.drawInputs();
227
+ const elements = ui.divV([plot.root, inputs]);
228
+
229
+ // Move detaching scatterplot to the grid.
230
+ plot.onEvent('d4-viewer-detached').subscribe((args) => {
231
+ let found = false;
232
+
233
+ for (const v of this.view.viewers) {
234
+ const opts = v.getOptions() as {[name: string]: any};
235
+
236
+ if (opts.type == 'Scatter plot' && opts.look.xColumnName == '~X' && opts.look.yColumnName == '~Y')
237
+ found = true;
238
+ }
239
+
240
+ if (!found)
241
+ this.view.addViewer(plot);
242
+ });
243
+
244
+ return new DG.Widget(elements);
226
245
  }
227
246
  }
@@ -3,6 +3,7 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import $ from 'cash-dom';
6
+ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
7
 
7
8
  import {model} from '../model';
8
9
 
@@ -28,7 +29,7 @@ export class SARViewer extends DG.JsViewer {
28
29
  protected viewerVGrid: DG.Grid | null;
29
30
  protected currentBitset: DG.BitSet | null;
30
31
  grouping: boolean;
31
- groupMapping: {[key: string]: string} | null;
32
+ groupMapping: StringDictionary | null;
32
33
  // protected pValueThreshold: number;
33
34
  // protected amountOfBestAARs: number;
34
35
  // duplicatesHandingMethod: string;
@@ -289,7 +290,7 @@ function applyBitset(
289
290
  dataFrame: DG.DataFrame,
290
291
  viewerGrid: DG.Grid,
291
292
  aminoAcidResidue: string,
292
- groupMapping: {[key: string]: string},
293
+ groupMapping: StringDictionary,
293
294
  initialBitset: DG.BitSet,
294
295
  filterMode: boolean,
295
296
  ) {
@@ -378,7 +379,7 @@ function accordionFunc(
378
379
  hist.style.width = 'auto';
379
380
  elements.push(hist);
380
381
 
381
- const tableMap: {[key: string]: string} = {'Statistics:': ''};
382
+ const tableMap: StringDictionary = {'Statistics:': ''};
382
383
  for (const colName of new Set(['Count', 'pValue', 'Mean difference'])) {
383
384
  const query = `${aminoAcidResidue} = ${currentAAR} and Position = ${currentPosition}`;
384
385
  const textNum = statsDf.groupBy([colName]).where(query).aggregate().get(colName, 0);
@@ -1,4 +1,4 @@
1
- // import * as grok from 'datagrok-api/grok';
1
+ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
@@ -6,6 +6,7 @@ import $ from 'cash-dom';
6
6
 
7
7
  // import {aarGroups} from '../describe';
8
8
  import {setAARRenderer} from '../utils/cell-renderer';
9
+ import { SemanticValue } from 'datagrok-api/dg';
9
10
 
10
11
  export class SubstViewer extends DG.JsViewer {
11
12
  viewerGrid: DG.Grid | null;
@@ -35,7 +36,7 @@ export class SubstViewer extends DG.JsViewer {
35
36
  const df: DG.DataFrame = this.dataFrame!;
36
37
  const col: DG.Column = df.columns.bySemType('alignedSequence');
37
38
  // let values: number[] = df.columns.byName('IC50').toList();
38
- const values = df.getCol(this.activityColumnName).toList().map((x) => -Math.log10(x));
39
+ const values = df.getCol(this.activityColumnName).toList();
39
40
  // values = values;
40
41
  const splitedMatrix = this.split(col);
41
42
 
@@ -123,6 +124,7 @@ export class SubstViewer extends DG.JsViewer {
123
124
  const tableValuesKeys = Object.keys(tableValues);
124
125
  const dfLength = tableValuesKeys.length;
125
126
  const cols = [...nColsArray.keys()].map((v) => DG.Column.int(v.toString(), dfLength));
127
+ cols.forEach((col: DG.Column) => col.semType = 'Substitution');
126
128
  const aarCol = DG.Column.string(aarColName, dfLength);
127
129
  cols.splice(0, 1, aarCol);
128
130
  const table = DG.DataFrame.fromColumns(cols);
@@ -200,8 +202,11 @@ export class SubstViewer extends DG.JsViewer {
200
202
 
201
203
  this.casesGrid = tempDf.plot.grid();
202
204
  this.casesGrid.props.allowEdit = false;
203
- } else
205
+ grok.shell.o = SemanticValue.fromValueType(tempDf, 'Substitution');
206
+ } else {
207
+ grok.shell.o = SemanticValue.fromValueType(null, 'Substitution');
204
208
  this.casesGrid = null;
209
+ }
205
210
 
206
211
  this.render();
207
212
  });
@@ -211,9 +216,7 @@ export class SubstViewer extends DG.JsViewer {
211
216
 
212
217
  render() {
213
218
  $(this.root).empty();
214
- this.root.appendChild(this.casesGrid === null ?
215
- this.viewerGrid!.root : ui.splitH([this.viewerGrid!.root, this.casesGrid.root]),
216
- );
219
+ this.root.appendChild(this.viewerGrid!.root);
217
220
  }
218
221
 
219
222
  split(peptideColumn: DG.Column, filter: boolean = true): string[][] {
@@ -3,6 +3,7 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
  import {Peptides} from '../peptides';
5
5
  import '../styles.css';
6
+ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
7
 
7
8
  /**
8
9
  * Peptide analysis widget.
@@ -77,7 +78,7 @@ export async function analyzePeptidesWidget(
77
78
  const startBtn = ui.button('Launch SAR', async () => {
78
79
  if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
79
80
  const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
80
- const options: {[key: string]: string} = {
81
+ const options: StringDictionary = {
81
82
  'activityColumnName': activityColumnChoice.value.name,
82
83
  'scaling': activityScalingMethod.value,
83
84
  };
@@ -1,4 +1,5 @@
1
1
  import {DimensionalityReducer, KnownMethods} from '@datagrok-libraries/ml/src/reduce-dimensionality';
2
+ import { KnownMetrics } from '@datagrok-libraries/ml/src/typed-metrics';
2
3
  import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
3
4
 
4
5
  /**
@@ -10,7 +11,7 @@ import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
10
11
  * @param {number} cyclesCount Number of cycles to repeat.
11
12
  * @return {Coordinates} Embedding.
12
13
  */
13
- function onMessage(columnData: [], method: KnownMethods, measure: string, cyclesCount: number): Coordinates {
14
+ function onMessage(columnData: any[], method: KnownMethods, measure: KnownMetrics, cyclesCount: number): Coordinates {
14
15
  const reducer = new DimensionalityReducer(
15
16
  columnData,
16
17
  method,