@datagrok/peptides 1.3.7 → 1.3.8

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.
@@ -14,28 +14,40 @@ import {scaleActivity} from '../utils/misc';
14
14
  * @param {DG.DataFrame} df Working table
15
15
  * @param {DG.Column} col Aligned sequence column
16
16
  * @return {Promise<DG.Widget>} Widget containing peptide analysis */
17
- export async function analyzePeptidesWidget(df: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
18
- if (!col.tags['aligned']?.includes('MSA') && col.tags[DG.TAGS.UNITS].toLowerCase() != 'helm')
19
- return new DG.Widget(ui.divText('Peptides analysis only works with aligned sequences'));
17
+ export async function analyzePeptidesUI(df: DG.DataFrame, col?: DG.Column<string>):
18
+ Promise<{host: HTMLElement, callback: () => Promise<void>}> {
19
+ let seqColInput: DG.InputBase | null = null;
20
+ if (typeof col === 'undefined') {
21
+ const sequenceColumns = df.columns.toList().filter((dfCol) => dfCol.semType === DG.SEMTYPE.MACROMOLECULE);
22
+ let potentialCol = DG.Utils.firstOrNull(sequenceColumns);
23
+ if (potentialCol === null)
24
+ throw new Error('Peptides Error: table doesn\'t contain sequence columns');
25
+ seqColInput = ui.columnInput('Sequence', df, potentialCol, () => {
26
+ const seqCol = seqColInput!.value;
27
+ if (!seqCol.tags['aligned']?.includes('MSA') && seqCol.tags[DG.TAGS.UNITS].toLowerCase() !== 'helm')
28
+ grok.shell.warning('Peptides analysis only works with aligned sequences');
29
+ });
30
+ } else if (!col.tags['aligned']?.includes('MSA') && col.tags[DG.TAGS.UNITS].toLowerCase() !== 'helm')
31
+ return {host: ui.label('Peptides analysis only works with aligned sequences'), callback: async () => {}};
20
32
 
21
33
  let funcs = DG.Func.find({package: 'Bio', name: 'webLogoViewer'});
22
34
  if (funcs.length == 0)
23
- return new DG.Widget(ui.label('Bio package is missing or out of date. Please install the latest version.'));
35
+ return {host: ui.label('Bio package is missing or out of date. Please install the latest version.'), callback: async () => {}};
24
36
 
25
- funcs = DG.Func.find({package: 'Helm', name: 'getMonomerLib'});
37
+ funcs = DG.Func.find({package: 'Bio', name: 'getBioLib'});
26
38
  if (funcs.length == 0)
27
- return new DG.Widget(ui.label('Helm package is missing or out of date. Please install the latest version.'));
39
+ return {host: ui.label('Bio package is missing or out of date. Please install the latest version.'), callback: async () => {}};
28
40
 
29
41
  let scaledCol: DG.Column<number>;
30
42
 
31
43
  const defaultActivityColumn: DG.Column<number> | null =
32
- df.col('activity') || df.col('IC50') || DG.Utils.firstOrNull(df.columns.numerical);;
44
+ df.col('activity') || df.col('IC50') || DG.Utils.firstOrNull(df.columns.numerical); ;
33
45
  const histogramHost = ui.div([], {id: 'pep-hist-host'});
34
46
 
35
47
  const activityScalingMethod = ui.choiceInput(
36
48
  'Scaling', 'none', ['none', 'lg', '-lg'],
37
49
  async (currentMethod: string): Promise<void> => {
38
- scaledCol = scaleActivity(currentMethod, activityColumnChoice.value!);
50
+ scaledCol = scaleActivity(activityColumnChoice.value!, currentMethod);
39
51
 
40
52
  const hist = DG.DataFrame.fromColumns([scaledCol]).plot.histogram({
41
53
  filteringEnabled: false,
@@ -62,37 +74,48 @@ export async function analyzePeptidesWidget(df: DG.DataFrame, col: DG.Column): P
62
74
  activityScalingMethod.fireChanged();
63
75
 
64
76
  const inputsList = [activityColumnChoice, activityScalingMethod, clustersColumnChoice];
77
+ if (seqColInput !== null)
78
+ inputsList.splice(0, 0, seqColInput);
65
79
 
66
80
  const bitsetChanged = df.filter.onChanged.subscribe(() => {
67
81
  activityScalingMethodState();
68
- })
82
+ });
69
83
 
70
- const startBtn = ui.button('Launch SAR', async () => {
71
- await startAnalysis(activityColumnChoice.value!, col, clustersColumnChoice.value, df, scaledCol,
72
- activityScalingMethod.value ?? 'none');
84
+ const startAnalysisCallback = async () => {
85
+ const sequencesCol = col ?? seqColInput!.value;
86
+ if (sequencesCol)
87
+ await startAnalysis(activityColumnChoice.value!, sequencesCol, clustersColumnChoice.value, df, scaledCol,
88
+ activityScalingMethod.value ?? 'none');
73
89
  bitsetChanged.unsubscribe();
74
- });
75
- startBtn.style.alignSelf = 'center';
90
+ };
91
+
92
+ const inputElements: HTMLElement[] = [ui.inputs(inputsList)];
93
+ $(inputElements[0]).find('label').css('width', 'unset');
94
+ if (typeof col !== 'undefined') {
95
+ const startBtn = ui.button('Launch SAR', startAnalysisCallback);
96
+ startBtn.style.alignSelf = 'center';
97
+ inputElements.push(startBtn);
98
+ }
76
99
 
77
100
  const viewer = await df.plot.fromType('WebLogo') as bio.WebLogoViewer;
78
101
  viewer.root.style.setProperty('height', '130px');
79
102
  const logoHost = ui.div();
80
103
  $(logoHost).empty().append(viewer.root);
81
104
 
82
- return new DG.Widget(
83
- ui.divV([
84
- logoHost,
85
- ui.splitH([
86
- ui.splitV([ui.inputs(inputsList), startBtn]),
87
- histogramHost,
88
- ], {style: {height: '215px'}}),
89
- ]),
90
- );
105
+ const mainHost = ui.divV([
106
+ logoHost,
107
+ ui.splitH([
108
+ ui.splitV(inputElements),
109
+ histogramHost,
110
+ ], {style: {height: '215px'}}),
111
+ ]);
112
+ mainHost.style.maxWidth = '400px';
113
+ return {host: mainHost, callback: startAnalysisCallback};
91
114
  }
92
115
 
93
116
  export async function startAnalysis(activityColumn: DG.Column<number>, peptidesCol: DG.Column<string>,
94
117
  clustersColumn: DG.Column | null, currentDf: DG.DataFrame, scaledCol: DG.Column<number>, scaling: string,
95
- ): Promise<PeptidesModel | null> {
118
+ ): Promise<PeptidesModel | null> {
96
119
  const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
97
120
  let model = null;
98
121
  if (activityColumn.type === DG.TYPE.FLOAT || activityColumn.type === DG.TYPE.INT) {
@@ -112,9 +135,9 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
112
135
  newDf.name = 'Peptides analysis';
113
136
  if (clustersColumn) {
114
137
  newDf.getCol(clustersColumn.name).name = C.COLUMNS_NAMES.CLUSTERS;
115
- newDf.tags[C.TAGS.CLUSTERS] = C.COLUMNS_NAMES.CLUSTERS;
138
+ newDf.setTag(C.TAGS.CLUSTERS, C.COLUMNS_NAMES.CLUSTERS);
116
139
  }
117
- newDf.tags['scaling'] = scaling;
140
+ newDf.setTag('settings', JSON.stringify({scaling: scaling}));
118
141
 
119
142
  let monomerType = 'HELM_AA';
120
143
  if (peptidesCol.getTag(DG.TAGS.UNITS).toLowerCase() == 'helm') {
@@ -0,0 +1,37 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as grok from 'datagrok-api/grok';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import * as type from '../utils/types';
6
+ import {PeptidesModel} from '../model';
7
+
8
+ //TODO: show sliderInput values
9
+ export function getSettingsDialog(model: PeptidesModel): DG.Dialog {
10
+ const settings = model.settings;
11
+ const result: type.PeptidesSettings = {};
12
+ const activityScaling = ui.choiceInput('Activity scaling', settings.scaling ?? 'none', ['none', 'lg', '-lg'],
13
+ () => result.scaling = activityScaling.value! as type.ScalingMethods);
14
+ const bidirectionalAnalysis = ui.boolInput('Bidirectional analysis', settings.isBidirectional ?? false,
15
+ () => result.isBidirectional = bidirectionalAnalysis.value!);
16
+ const maxMutations = ui.sliderInput('Max mutations', settings.maxMutations ?? 1, 0, 50, () => {
17
+ const val = Math.round(maxMutations.value!);
18
+ result.maxMutations = val;
19
+ });
20
+ const minActivityDelta = ui.sliderInput('Min activity delta', settings.minActivityDelta ?? 0, 0, 100, () => {
21
+ const val = Math.round(minActivityDelta.value!);
22
+ result.minActivityDelta = val;
23
+ });
24
+
25
+ const accordion = ui.accordion();
26
+ accordion.addPane('General', () => ui.inputs([activityScaling, bidirectionalAnalysis]), true);
27
+ accordion.addPane('Mutation Cliffs', () => ui.inputs([maxMutations, minActivityDelta]), true);
28
+
29
+ const dialog = ui.dialog('Peptides settings').add(accordion);
30
+ dialog.root.style.width = '400px';
31
+ dialog.onOK(() => model.settings = result);
32
+ dialog.show();
33
+
34
+ return dialog.show();
35
+ }
36
+
37
+