@datagrok/peptides 0.6.0 → 0.6.1

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/detectors.js CHANGED
@@ -3,7 +3,7 @@ class PeptidesPackageDetectors extends DG.Package {
3
3
  //input: column col
4
4
  //output: string semType
5
5
  detectAligned(col) {
6
- const regexp = new RegExp(/^([^-^\n]*-){2,49}(\w|\(|\))+$/);
6
+ const regexp = new RegExp(/^([^-^\n]*-){7,49}(\w|\(|\))+$/);
7
7
  return DG.Detector.sampleCategories(col, (s) => regexp.test(s.trim())) ? 'alignedSequence' : null;
8
8
  }
9
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "",
5
5
  "dependencies": {
6
6
  "@keckelt/tsne": "^1.0.2",
@@ -21,6 +21,8 @@
21
21
  "devDependencies": {
22
22
  "typescript": "^4.4.4",
23
23
  "ts-loader": "^9.2.5",
24
+ "css-loader": "^5.2.4",
25
+ "style-loader": "^2.0.0",
24
26
  "@typescript-eslint/eslint-plugin": "^4.29.1",
25
27
  "@typescript-eslint/parser": "^4.29.1",
26
28
  "eslint": "^7.32.0",
package/src/describe.ts CHANGED
@@ -178,7 +178,7 @@ export async function describe(
178
178
 
179
179
  //calculate p-values based on t-test
180
180
  let position: string;
181
- let AAR: string;
181
+ let aar: string;
182
182
  let currentActivity: number[];
183
183
  let otherActivity: number[];
184
184
  let testResult;
@@ -190,17 +190,17 @@ export async function describe(
190
190
  const pValCol: DG.Column = matrixDf.columns.addNewFloat('pValue');
191
191
  for (let i = 0; i < matrixDf.rowCount; i++) {
192
192
  position = matrixDf.get(positionColName, i);
193
- AAR = matrixDf.get(aminoAcidResidue, i);
193
+ aar = matrixDf.get(aminoAcidResidue, i);
194
194
 
195
195
  //@ts-ignore
196
- splitSeqDf.rows.select((row) => groupMapping[row[position]] === AAR);
196
+ splitSeqDf.rows.select((row) => groupMapping[row[position]] === aar);
197
197
  currentActivity = splitSeqDf
198
198
  .clone(splitSeqDf.selection, [activityColumnScaled])
199
199
  .getCol(activityColumnScaled)
200
200
  .toList();
201
201
 
202
202
  //@ts-ignore
203
- splitSeqDf.rows.select((row) => groupMapping[row[position]] !== AAR);
203
+ splitSeqDf.rows.select((row) => groupMapping[row[position]] !== aar);
204
204
  otherActivity = splitSeqDf
205
205
  .clone(splitSeqDf.selection, [activityColumnScaled])
206
206
  .getCol(activityColumnScaled)
@@ -271,23 +271,23 @@ export async function describe(
271
271
  renderColNames.push('Mean difference');
272
272
 
273
273
  // !!! DRAWING PHASE !!!
274
- const SARgrid = matrixDf.plot.grid();
275
- SARgrid.sort([aminoAcidResidue]);
276
- SARgrid.columns.setOrder([aminoAcidResidue].concat(positionColumns));
274
+ const sarGrid = matrixDf.plot.grid();
275
+ sarGrid.sort([aminoAcidResidue]);
276
+ sarGrid.columns.setOrder([aminoAcidResidue].concat(positionColumns));
277
277
 
278
- const SARVgrid = sequenceDf.plot.grid();
279
- SARVgrid.sort([positionColName]);
280
- SARVgrid.col('pValue')!.format = 'four digits after comma';
281
- SARVgrid.col('pValue')!.name = 'P-Value';
278
+ const sarVGrid = sequenceDf.plot.grid();
279
+ sarVGrid.sort([positionColName]);
280
+ sarVGrid.col('pValue')!.format = 'four digits after comma';
281
+ sarVGrid.col('pValue')!.name = 'P-Value';
282
282
 
283
283
  if (!grouping) {
284
284
  let tempCol = matrixDf.columns.byName(aminoAcidResidue);
285
285
  if (tempCol) {
286
- setAARRenderer(tempCol, SARgrid);
286
+ setAARRenderer(tempCol, sarGrid);
287
287
  }
288
288
  tempCol = sequenceDf.columns.byName(aminoAcidResidue);
289
289
  if (tempCol) {
290
- setAARRenderer(tempCol, SARgrid);
290
+ setAARRenderer(tempCol, sarGrid);
291
291
  }
292
292
  }
293
293
 
@@ -358,8 +358,8 @@ export async function describe(
358
358
  }
359
359
  args.g.restore();
360
360
  };
361
- SARgrid.onCellRender.subscribe(cellRendererFunc);
362
- SARVgrid.onCellRender.subscribe(cellRendererFunc);
361
+ sarGrid.onCellRender.subscribe(cellRendererFunc);
362
+ sarVGrid.onCellRender.subscribe(cellRendererFunc);
363
363
 
364
364
  // show all the statistics in a tooltip over cell
365
365
  const onCellTooltipFunc = function(cell: DG.GridCell, x: number, y: number) {
@@ -412,8 +412,8 @@ export async function describe(
412
412
  }
413
413
  return true;
414
414
  };
415
- SARgrid.onCellTooltip(onCellTooltipFunc);
416
- SARVgrid.onCellTooltip(onCellTooltipFunc);
415
+ sarGrid.onCellTooltip(onCellTooltipFunc);
416
+ sarVGrid.onCellTooltip(onCellTooltipFunc);
417
417
 
418
418
  sourceGrid.onCellPrepare((cell: DG.GridCell) => {
419
419
  const currentRowIndex = cell.tableRowIndex;
@@ -423,13 +423,16 @@ export async function describe(
423
423
  });
424
424
 
425
425
  for (const col of matrixDf.columns.names()) {
426
- SARgrid.col(col)!.width = SARgrid.props.rowHeight;
426
+ sarGrid.col(col)!.width = sarGrid.props.rowHeight;
427
427
  }
428
428
 
429
429
  if (grouping) {
430
- SARgrid.col(aminoAcidResidue)!.name = 'Groups';
431
- SARVgrid.col(aminoAcidResidue)!.name = 'Groups';
430
+ sarGrid.col(aminoAcidResidue)!.name = 'Groups';
431
+ sarVGrid.col(aminoAcidResidue)!.name = 'Groups';
432
432
  }
433
433
 
434
- return [SARgrid, SARVgrid, statsDf, groupMapping];
434
+ sarGrid.props.allowEdit = false;
435
+ sarVGrid.props.allowEdit = false;
436
+
437
+ return [sarGrid, sarVGrid, statsDf, groupMapping];
435
438
  }
package/src/package.ts CHANGED
@@ -16,7 +16,7 @@ import {manualAlignmentWidget} from './widgets/manual-alignment';
16
16
  import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
17
17
  import {peptideMoleculeWidget} from './widgets/peptide-molecule';
18
18
  import {SpiralPlot} from './viewers/spiral-plot';
19
- import { SubstViewer } from './viewers/subst-viewer';
19
+ import {SubstViewer} from './viewers/subst-viewer';
20
20
 
21
21
  export const _package = new DG.Package();
22
22
  let tableGrid: DG.Grid;
@@ -64,25 +64,18 @@ export function Peptides() {
64
64
  'Use and analyse peptide sequence data to support your research:',
65
65
  );
66
66
 
67
- const annotationViewerDiv = ui.div();
68
-
69
67
  const windows = grok.shell.windows;
70
68
  windows.showToolbox = false;
71
69
  windows.showHelp = false;
72
70
  windows.showProperties = false;
73
71
 
74
- const mainDiv = ui.div();
75
72
  grok.shell.newView('Peptides', [
76
73
  appDescription,
77
74
  ui.info([textLink]),
78
- ui.div([
79
- ui.block25([
80
- ui.button('Open peptide sequences demonstration set', () => main('aligned.csv'), ''),
81
- ui.button('Open complex case demo', () => main('aligned_2.csv'), ''),
82
- ]),
83
- ui.block75([annotationViewerDiv]),
75
+ ui.divH([
76
+ ui.button('Open peptide sequences demonstration set', () => main('aligned.csv'), ''),
77
+ ui.button('Open complex case demo', () => main('aligned_2.csv'), ''),
84
78
  ]),
85
- mainDiv,
86
79
  ]);
87
80
  }
88
81
 
@@ -91,6 +84,9 @@ export function Peptides() {
91
84
  //input: column col {semType: alignedSequence}
92
85
  //output: widget result
93
86
  export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
87
+ if (col.getTag('isAnalysisApplicable') === 'false') {
88
+ return new DG.Widget(ui.divText('Analysis is not applicable'));
89
+ }
94
90
  view = (grok.shell.v as DG.TableView);
95
91
  tableGrid = view.grid;
96
92
  currentDf = col.dataFrame;
package/src/peptides.ts CHANGED
@@ -2,6 +2,7 @@ import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import {createPeptideSimilaritySpaceViewer} from './utils/peptide-similarity-space';
4
4
  import {addViewerToHeader} from './viewers/stacked-barchart-viewer';
5
+ // import $ from 'cash-dom';
5
6
 
6
7
  /**
7
8
  * Peptides controller class.
@@ -41,9 +42,10 @@ export class Peptides {
41
42
  }
42
43
 
43
44
  const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
45
+ const originalDfName = currentDf.name;
44
46
 
45
47
  const substViewer = view.addViewer(
46
- 'substitution-analysis-viewer', {'activityColumnName': options['activityColumnColumnName']},
48
+ 'substitution-analysis-viewer', {'activityColumnName': options['activityColumnName']},
47
49
  );
48
50
  view.dockManager.dock(substViewer, DG.DOCK_TYPE.RIGHT, null, 'Substitution Analysis');
49
51
 
@@ -62,10 +64,13 @@ export class Peptides {
62
64
  view,
63
65
  `${activityColumnChoice}Scaled`,
64
66
  );
65
- view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
67
+ const psNode = view.dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.LEFT, sarNode, 'Peptide Space Viewer', 0.3);
68
+ // const sarDockNodes = [sarNode, sarVNode, psNode];
69
+ // const sarViewers = [sarViewer, sarViewerVertical, peptideSpaceViewer];
66
70
 
67
71
  const StackedBarchartProm = currentDf.plot.fromType('StackedBarChartAA');
68
72
  addViewerToHeader(tableGrid, StackedBarchartProm);
73
+ tableGrid.props.allowEdit = false;
69
74
 
70
75
  const hideIcon = ui.iconFA('window-close', () => { //undo?, times?
71
76
  const viewers = [];
@@ -88,10 +93,47 @@ export class Peptides {
88
93
 
89
94
  tableGrid.setOptions({'colHeaderHeight': 20});
90
95
  tableGrid.columns.setVisible(originalDfColumns);
96
+ tableGrid.props.allowEdit = true;
97
+ currentDf.name = originalDfName;
91
98
 
92
99
  view.setRibbonPanels(ribbonPanels);
93
100
  }, 'Close viewers and restore dataframe');
94
101
 
102
+ // let substViewer: DG.Viewer | null = null;
103
+ // let substNode: DG.DockNode | null = null;
104
+ // let isSA = false;
105
+ // let viewLayout1: DG.ViewLayout | null = null;
106
+ // let viewLayout2: DG.ViewLayout | null = null;
107
+ // const switchViewers = ui.iconFA('toggle-on', () => {
108
+ // if (isSA) {
109
+ // viewLayout2 = view.saveLayout();
110
+ // // view.dockManager.close(substNode!);
111
+ // substViewer?.close();
112
+
113
+ // view.loadLayout(viewLayout1!);
114
+
115
+ // $(switchViewers).removeClass('fa-toggle-off');
116
+ // $(switchViewers).addClass('fa-toggle-on');
117
+ // } else {
118
+ // viewLayout1 = view.saveLayout();
119
+ // // sarDockNodes.forEach((node) => view.dockManager.close(node));
120
+ // sarViewers.forEach((v) => v.close());
121
+
122
+ // if (viewLayout2 === null) {
123
+ // substViewer = view.addViewer(
124
+ // 'substitution-analysis-viewer', {'activityColumnName': options['activityColumnName']},
125
+ // );
126
+ // substNode = view.dockManager.dock(substViewer, DG.DOCK_TYPE.DOWN, null, 'Substitution Analysis');
127
+ // } else {
128
+ // view.loadLayout(viewLayout2);
129
+ // }
130
+
131
+ // $(switchViewers).removeClass('fa-toggle-on');
132
+ // $(switchViewers).addClass('fa-toggle-off');
133
+ // }
134
+ // isSA = !isSA;
135
+ // });
136
+
95
137
  const ribbonPanels = view.getRibbonPanels();
96
138
  view.setRibbonPanels([[hideIcon]]);
97
139
  }
package/src/styles.css ADDED
@@ -0,0 +1,37 @@
1
+ .pep-textarea-box {
2
+ position: relative;
3
+ }
4
+
5
+ .pep-textarea-box:hover .pep-snippet-editor-icon {
6
+ visibility: visible;
7
+ }
8
+
9
+ .pep-snippet-editor-icon {
10
+ position: absolute;
11
+ top: 5px;
12
+ visibility: hidden;
13
+ margin: 5px;
14
+ z-index: 1;
15
+ }
16
+
17
+ .pep-reset-icon {
18
+ right: 10px;
19
+ }
20
+
21
+ .pep-snippet-editor-icon i {
22
+ font-size: 13px;
23
+ }
24
+
25
+ .pep-snippet-editor-icon:hover {
26
+ background-color: var(--steel-1);
27
+ border-radius: 2px;
28
+ }
29
+
30
+ .pep-snippet-inline-icon i {
31
+ font-size: 13px;
32
+ }
33
+
34
+ .pep-textinput {
35
+ height: 50px;
36
+ overflow: hidden;
37
+ }
@@ -56,7 +56,7 @@ export class ChemPalette {
56
56
  /**
57
57
  * Get color for the provided amino acid residue.
58
58
  * @param {string} c Amino acid residue string.
59
- * @returns {string} Color.
59
+ * @return {string} Color.
60
60
  */
61
61
  getColor(c: string): string {
62
62
  const [color] = this.getColorPivot(c);
@@ -66,7 +66,7 @@ export class ChemPalette {
66
66
  /**
67
67
  * Get color for the provided amino acid residue pivot
68
68
  * @param {string} [c=''] Amino acid residue string.
69
- * @returns {[string, string, number]}
69
+ * @return {[string, string, number]}
70
70
  */
71
71
  getColorAAPivot(c: string = ''): [string, string, number] {
72
72
  if (c.length == 1 || c[1] == '(') {
@@ -16,8 +16,8 @@ import {model} from './model';
16
16
  export class SARViewer extends DG.JsViewer {
17
17
  protected viewerGrid: DG.Grid | null;
18
18
  protected sourceGrid: DG.Grid | null;
19
- protected activityColumnColumnName: string;
20
- protected activityScalingMethod: string;
19
+ protected activityColumnName: string;
20
+ protected scaling: string;
21
21
  protected bidirectionalAnalysis: boolean;
22
22
  protected filterMode: boolean;
23
23
  protected statsDf: DG.DataFrame | null;
@@ -51,9 +51,9 @@ export class SARViewer extends DG.JsViewer {
51
51
  this.viewGridInitialized = false;
52
52
  this.currentBitset = null;
53
53
 
54
- //TODO: find a way to restrict activityColumnColumnName to accept only numerical columns (double even better)
55
- this.activityColumnColumnName = this.string('activityColumnColumnName');
56
- this.activityScalingMethod = this.string('activityScalingMethod', 'none', {choices: ['none', 'lg', '-lg']});
54
+ //TODO: find a way to restrict activityColumnName to accept only numerical columns (double even better)
55
+ this.activityColumnName = this.string('activityColumnName');
56
+ this.scaling = this.string('scaling', 'none', {choices: ['none', 'lg', '-lg']});
57
57
  this.filterMode = this.bool('filterMode', false);
58
58
  this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
59
59
  this.grouping = this.bool('grouping', false);
@@ -115,14 +115,14 @@ export class SARViewer extends DG.JsViewer {
115
115
  return;
116
116
  }
117
117
 
118
- if (property.name === 'activityScalingMethod' && typeof this.dataFrame !== 'undefined') {
118
+ if (property.name === 'scaling' && typeof this.dataFrame !== 'undefined') {
119
119
  const minActivity = DG.Stats.fromColumn(
120
- this.dataFrame!.col(this.activityColumnColumnName)!,
120
+ this.dataFrame!.col(this.activityColumnName)!,
121
121
  this._initialBitset,
122
122
  ).min;
123
- if (minActivity && minActivity <= 0 && this.activityScalingMethod !== 'none') {
124
- grok.shell.warning(`Could not apply ${this.activityScalingMethod}: ` +
125
- `activity column ${this.activityColumnColumnName} contains zero or negative values, falling back to 'none'.`);
123
+ if (minActivity && minActivity <= 0 && this.scaling !== 'none') {
124
+ grok.shell.warning(`Could not apply ${this.scaling}: ` +
125
+ `activity column ${this.activityColumnName} contains zero or negative values, falling back to 'none'.`);
126
126
  property.set(this, 'none');
127
127
  return;
128
128
  }
@@ -230,7 +230,7 @@ export class SARViewer extends DG.JsViewer {
230
230
  const hist = originalDf.clone(this._initialBitset).plot.histogram({
231
231
  // const hist = originalDf.plot.histogram({
232
232
  filteringEnabled: false,
233
- valueColumnName: `${this.activityColumnColumnName}Scaled`,
233
+ valueColumnName: `${this.activityColumnName}Scaled`,
234
234
  splitColumnName: '~splitCol',
235
235
  legendVisibility: 'Never',
236
236
  showXAxis: true,
@@ -317,11 +317,11 @@ export class SARViewer extends DG.JsViewer {
317
317
  }
318
318
  //TODO: optimize. Don't calculate everything again if only view changes
319
319
  if (computeData) {
320
- if (typeof this.dataFrame !== 'undefined' && this.activityColumnColumnName && this.sourceGrid) {
320
+ if (typeof this.dataFrame !== 'undefined' && this.activityColumnName && this.sourceGrid) {
321
321
  await model?.updateData(
322
322
  this.dataFrame!,
323
- this.activityColumnColumnName,
324
- this.activityScalingMethod,
323
+ this.activityColumnName,
324
+ this.scaling,
325
325
  this.sourceGrid,
326
326
  this.bidirectionalAnalysis,
327
327
  this._initialBitset,
@@ -1,11 +1,11 @@
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
 
5
5
  import $ from 'cash-dom';
6
6
 
7
- import { aarGroups } from '../describe';
8
- import { setAARRenderer } from '../utils/cell-renderer';
7
+ // import {aarGroups} from '../describe';
8
+ import {setAARRenderer} from '../utils/cell-renderer';
9
9
 
10
10
  export class SubstViewer extends DG.JsViewer {
11
11
  viewerGrid: DG.Grid | null;
@@ -32,28 +32,27 @@ export class SubstViewer extends DG.JsViewer {
32
32
 
33
33
  calcSubstitutions() {
34
34
  const aarColName = 'AAR';
35
- let splitedMatrix: string[][];
36
- let df: DG.DataFrame = this.dataFrame!;
35
+ const df: DG.DataFrame = this.dataFrame!;
37
36
  const col: DG.Column = df.columns.bySemType('alignedSequence');
38
37
  // let values: number[] = df.columns.byName('IC50').toList();
39
- const values = df.getCol(this.activityColumnName).toList().map(x => -Math.log10(x));
38
+ const values = df.getCol(this.activityColumnName).toList().map((x) => -Math.log10(x));
40
39
  // values = values;
41
- splitedMatrix = this.split(col);
40
+ const splitedMatrix = this.split(col);
42
41
 
43
- let tableValues: { [aar: string]: number[] } = {};
44
- let tableTooltips: { [aar: string]: string[] } = {};
45
- let tableCases: { [aar: string]: number[][][] } = {};
42
+ const tableValues: { [aar: string]: number[] } = {};
43
+ const tableTooltips: { [aar: string]: {[index: string]: string}[][] } = {};
44
+ const tableCases: { [aar: string]: number[][][] } = {};
46
45
 
47
- let nRows = splitedMatrix.length;
48
- let nCols = splitedMatrix[0].length;
46
+ const nRows = splitedMatrix.length;
47
+ const nCols = splitedMatrix[0].length;
49
48
  const nColsArray = Array(nCols);
50
49
 
51
50
  for (let i = 0; i < nRows - 1; i++) {
52
51
  for (let j = i + 1; j < nRows; j++) {
53
52
  let substCounter = 0;
54
- let subst1: { [pos: number]: [string, string] } = {};
55
- let subst2: { [pos: number]: [string, string] } = {};
56
- let delta = values[i] - values[j];
53
+ const subst1: { [pos: number]: [string, {[index: string]: string}] } = {};
54
+ const subst2: { [pos: number]: [string, {[index: string]: string}] } = {};
55
+ const delta = values[i] - values[j];
57
56
 
58
57
  for (let k = 0; k < nCols; k++) {
59
58
  const smik = splitedMatrix[i][k];
@@ -62,53 +61,76 @@ export class SubstViewer extends DG.JsViewer {
62
61
  const vi = values[i].toFixed(2);
63
62
  const vj = values[j].toFixed(2);
64
63
  substCounter++;
65
- subst1[k] = [smik, `${smik} -> ${smjk}\t\t${vi} -> ${vj}`];
66
- subst2[k] = [smjk, `${smjk} -> ${smik}\t\t${vj} -> ${vi}`];
64
+ subst1[k] = [
65
+ smik,
66
+ {key: `${smik === '-' ? 'Empty' : smik} → ${smjk === '-' ? 'Empty' : smjk}`, value: `${vi} → ${vj}`},
67
+ ];
68
+ subst2[k] = [
69
+ smjk,
70
+ {key: `${smjk === '-' ? 'Empty' : smjk} → ${smik === '-' ? 'Empty' : smik}`, value: `${vj} → ${vi}`},
71
+ ];
67
72
  }
68
73
  }
69
74
 
70
75
  if (substCounter <= this.maxSubstitutions && substCounter > 0) {
71
-
72
76
  Object.keys(subst1).forEach((pos) => {
73
77
  const posInt = parseInt(pos);
74
- let aar = subst1[posInt][0];
78
+ const aar = subst1[posInt][0];
75
79
  if (!Object.keys(tableValues).includes(aar)) {
76
- tableValues[aar] = Array.apply(null, nColsArray).map(function () { return DG.INT_NULL; });
77
- tableTooltips[aar] = Array.apply(null, nColsArray).map(function () { return ""; });
78
- tableCases[aar] = Array.apply(null, nColsArray).map(function () { return []; });
80
+ tableValues[aar] = Array.apply(null, nColsArray).map(function() {
81
+ return DG.INT_NULL;
82
+ });
83
+ tableTooltips[aar] = Array.apply(null, nColsArray).map(function() {
84
+ return [];
85
+ });
86
+ tableCases[aar] = Array.apply(null, nColsArray).map(function() {
87
+ return [];
88
+ });
79
89
  }
80
90
 
81
91
  tableValues[aar][posInt] = tableValues[aar][posInt] === DG.INT_NULL ? 1 : tableValues[aar][posInt] + 1;
82
- tableTooltips[aar][posInt] = tableTooltips[aar][posInt] == "" ? "Substitution\tvalues\n" : tableTooltips[aar][posInt];
83
- tableTooltips[aar][posInt] += subst1[posInt][1] + "\n";
92
+ tableTooltips[aar][posInt] = !tableTooltips[aar][posInt].length ?
93
+ [{key: 'Substitution', value: 'Values'}] : tableTooltips[aar][posInt];
94
+ tableTooltips[aar][posInt].push(subst1[posInt][1]);
84
95
  tableCases[aar][posInt].push([i, j, delta]);
85
96
  });
86
97
  Object.keys(subst2).forEach((pos) => {
87
98
  const posInt = parseInt(pos);
88
- let aar = subst2[posInt][0];
99
+ const aar = subst2[posInt][0];
89
100
  if (!Object.keys(tableValues).includes(aar)) {
90
- tableValues[aar] = Array.apply(null, nColsArray).map(function () { return DG.INT_NULL; });
91
- tableTooltips[aar] = Array.apply(null, nColsArray).map(function () { return ""; });
92
- tableCases[aar] = Array.apply(null, nColsArray).map(function () { return []; });
101
+ tableValues[aar] = Array.apply(null, nColsArray).map(function() {
102
+ return DG.INT_NULL;
103
+ });
104
+ tableTooltips[aar] = Array.apply(null, nColsArray).map(function() {
105
+ return [];
106
+ });
107
+ tableCases[aar] = Array.apply(null, nColsArray).map(function() {
108
+ return [];
109
+ });
93
110
  }
94
111
 
95
112
  tableValues[aar][posInt] = tableValues[aar][posInt] === DG.INT_NULL ? 1 : tableValues[aar][posInt] + 1;
96
113
  // tableValues[aar][posInt]++;
97
- tableTooltips[aar][posInt] = tableTooltips[aar][posInt] == "" ? "Substitution\tValues\n" : tableTooltips[aar][posInt];
98
- tableTooltips[aar][posInt] += subst2[posInt][1] + "\n";
114
+ tableTooltips[aar][posInt] = !tableTooltips[aar][posInt].length ?
115
+ [{key: 'Substitution', value: 'Values'}] : tableTooltips[aar][posInt];
116
+ tableTooltips[aar][posInt].push(subst2[posInt][1]);
99
117
  tableCases[aar][posInt].push([j, i, -delta]);
100
118
  });
101
119
  }
102
120
  }
103
121
  }
104
122
 
105
- const cols = [...Array(nCols).keys()].map((v) => DG.Column.int(v.toString()));
106
- const aarCol = DG.Column.string(aarColName);
123
+ const tableValuesKeys = Object.keys(tableValues);
124
+ const dfLength = tableValuesKeys.length;
125
+ const cols = [...nColsArray.keys()].map((v) => DG.Column.int(v.toString(), dfLength));
126
+ const aarCol = DG.Column.string(aarColName, dfLength);
107
127
  cols.splice(0, 1, aarCol);
108
- let table = DG.DataFrame.fromColumns(cols);
109
- for (const aar of Object.keys(tableValues)) {
128
+ const table = DG.DataFrame.fromColumns(cols);
129
+
130
+ for (let i = 0; i < dfLength; i++) {
131
+ const aar = tableValuesKeys[i];
110
132
  tableValues[aar].splice(0, 1);
111
- table.rows.addNew([aar, ...tableValues[aar]]);
133
+ table.rows.setValues(i, [aar, ...tableValues[aar]]);
112
134
  }
113
135
 
114
136
  // let groupMapping: { [key: string]: string } = {};
@@ -127,12 +149,15 @@ export class SubstViewer extends DG.JsViewer {
127
149
  if (colName !== aarColName) {
128
150
  const aar = this.viewerGrid!.table.get(aarColName, gCell.tableRowIndex);
129
151
  const pos = parseInt(colName);
130
- const tooltipText = tableTooltips[aar][pos];
131
- ui.tooltip.show(ui.divText(tooltipText ? tooltipText : 'No substitutions'), x, y);
152
+ const tooltipText = tableTooltips[aar][pos].length ?
153
+ DG.HtmlTable.create(
154
+ tableTooltips[aar][pos], (item: {[index: string]: string}, idx: number) => [item.key, item.value],
155
+ ).root : ui.divText('No substitutions');
156
+ ui.tooltip.show(tooltipText, x, y);
132
157
  }
133
158
  }
134
159
  return true;
135
- }
160
+ },
136
161
  );
137
162
 
138
163
  for (const col of table.columns.names()) {
@@ -146,28 +171,35 @@ export class SubstViewer extends DG.JsViewer {
146
171
  }
147
172
  });
148
173
 
174
+ this.viewerGrid.props.allowEdit = false;
175
+
149
176
  table.onCurrentCellChanged.subscribe((_) => {
150
177
  if (table.currentCol !== null && table.currentCol.name !== aarColName && table.currentCell.value !== null) {
151
178
  const aar = table.get(aarColName, table.currentRowIdx);
152
179
  const pos = parseInt(table.currentCol.name);
153
180
  const currentCase = tableCases[aar][pos];
154
- const initCol = DG.Column.string('Initial');
155
- const subsCol = DG.Column.string('Substituted');
181
+ const tempDfLength = currentCase.length;
182
+ const initCol = DG.Column.string('Initial', tempDfLength);
183
+ const subsCol = DG.Column.string('Substituted', tempDfLength);
156
184
 
157
185
  const tempDf = DG.DataFrame.fromColumns([
158
186
  initCol,
159
187
  subsCol,
160
- DG.Column.float('Difference'),
188
+ DG.Column.float('Difference', tempDfLength),
161
189
  ]);
162
190
 
163
- for (const row of currentCase) {
164
- tempDf.rows.addNew([col.get(row[0]), col.get(row[1]), row[2]]);
191
+ for (let i = 0; i < tempDfLength; i++) {
192
+ const row = currentCase[i];
193
+ tempDf.rows.setValues(i, [col.get(row[0]), col.get(row[1]), row[2]]);
165
194
  }
166
195
 
167
196
  initCol.semType = 'alignedSequence';
197
+ initCol.setTag('isAnalysisApplicable', 'false');
168
198
  subsCol.semType = 'alignedSequence';
199
+ subsCol.setTag('isAnalysisApplicable', 'false');
169
200
 
170
201
  this.casesGrid = tempDf.plot.grid();
202
+ this.casesGrid.props.allowEdit = false;
171
203
  } else {
172
204
  this.casesGrid = null;
173
205
  }
@@ -180,7 +212,7 @@ export class SubstViewer extends DG.JsViewer {
180
212
  render() {
181
213
  $(this.root).empty();
182
214
  this.root.appendChild(this.casesGrid === null ?
183
- this.viewerGrid!.root : ui.splitH([this.viewerGrid!.root, this.casesGrid.root])
215
+ this.viewerGrid!.root : ui.splitH([this.viewerGrid!.root, this.casesGrid.root]),
184
216
  );
185
217
  }
186
218
 
@@ -207,7 +239,7 @@ export class SubstViewer extends DG.JsViewer {
207
239
  // and marking invalid sequences
208
240
  let nTerminal: string;
209
241
  const invalidIndexes: number[] = [];
210
- let splitColumns: string[][] = Array.from({ length: modeMonomerCount }, (_) => []);
242
+ let splitColumns: string[][] = Array.from({length: modeMonomerCount}, (_) => []);
211
243
  modeMonomerCount--; // minus N-terminal
212
244
  for (let i = 0; i < colLength; i++) {
213
245
  currentSplitPeptide = splitPeptidesArray[i];
@@ -224,7 +256,7 @@ export class SubstViewer extends DG.JsViewer {
224
256
  modeMonomerCount--; // minus C-terminal
225
257
 
226
258
  //create column names list
227
- const columnNames = Array.from({ length: modeMonomerCount }, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1}`);
259
+ const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1}`);
228
260
  columnNames.splice(0, 0, 'N-terminal');
229
261
  columnNames.push('C-terminal');
230
262
 
@@ -76,8 +76,8 @@ export async function analyzePeptidesWidget(
76
76
  if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
77
77
  const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
78
78
  const options: {[key: string]: string} = {
79
- 'activityColumnColumnName': activityColumnChoice.value.name,
80
- 'activityScalingMethod': activityScalingMethod.value,
79
+ 'activityColumnName': activityColumnChoice.value.name,
80
+ 'scaling': activityScalingMethod.value,
81
81
  };
82
82
 
83
83
  const peptides = new Peptides();
@@ -4,18 +4,18 @@ import * as DG from 'datagrok-api/dg';
4
4
  import $ from 'cash-dom';
5
5
  import {model} from '../viewers/model';
6
6
  import {splitAlignedPeptides} from '../utils/split-aligned';
7
+ import '../styles.css';
7
8
 
8
9
  /**
9
10
  * Manual sequence alignment widget.
10
11
  *
11
12
  * @param {DG.Column} alignedSequenceCol Aligned sequence column.
12
13
  * @param {DG.DataFrame} currentDf Working table.
13
- * @returns {DG.Widget} Widget for manual sequence alignment.
14
+ * @return {DG.Widget} Widget for manual sequence alignment.
14
15
  */
15
16
  export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf: DG.DataFrame) {
16
17
  const sequenceInput = ui.textInput('', alignedSequenceCol.get(currentDf.currentRowIdx));
17
- (sequenceInput.input as HTMLElement).style.height = '50px';
18
- (sequenceInput.input as HTMLElement).style.overflow = 'hidden';
18
+ $(sequenceInput.root).addClass('pep-textinput');
19
19
 
20
20
  const applyChangesBtn = ui.button('Apply', async () => {
21
21
  const newSequence = sequenceInput.value;
@@ -37,7 +37,7 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf:
37
37
  () => sequenceInput.value = alignedSequenceCol.get(currentDf.currentRowIdx),
38
38
  'Reset',
39
39
  );
40
- $(resetBtn).addClass('dt-snippet-editor-icon dt-reset-icon');
40
+ $(resetBtn).addClass('pep-snippet-editor-icon pep-reset-icon');
41
41
 
42
- return new DG.Widget(ui.divV([resetBtn, sequenceInput.root, applyChangesBtn], 'dt-textarea-box'));
42
+ return new DG.Widget(ui.divV([resetBtn, sequenceInput.root, applyChangesBtn], 'pep-textarea-box'));
43
43
  }
package/webpack.config.js CHANGED
@@ -12,6 +12,10 @@ module.exports = {
12
12
  use: 'ts-loader',
13
13
  exclude: /node_modules/,
14
14
  },
15
+ {
16
+ test: /\.css$/i,
17
+ use: ['style-loader', 'css-loader'],
18
+ },
15
19
  ],
16
20
  },
17
21
  resolve: {