Skip to content

Commit eb14500

Browse files
authored
Add settings history in web application (#301)
* add history * add dict source to rfu app * add log download * add differential hdx settings
1 parent 4ef586a commit eb14500

File tree

6 files changed

+296
-41
lines changed

6 files changed

+296
-41
lines changed

dev/gui/dev_gui_secB.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
from pyhdx.web.utils import load_state, fix_multiindex_dtypes
2222
from pyhdx.config import cfg, reset_config
2323

24-
reset_config()
25-
2624
#def printfunc(args):
2725
# 1/0
2826

@@ -132,24 +130,21 @@ def init_dashboard():
132130
input_control._action_load_datasets()
133131

134132
d_uptake_control = ctrl.control_panels["DUptakeFitControl"]
135-
d_uptake_control.repeats = 3
136-
133+
d_uptake_control.repeats = 2
137134

138135
ctrl.sources['pdb'].add_from_string(pdb_string, '1qyn')
139136

140137
src = ctrl.sources['main']
141-
df = csv_to_dataframe(web_data_dir / 'd_uptake.csv')
142-
df.columns = fix_multiindex_dtypes(df.columns)
143-
src.add_table('d_uptake', df)
144-
src.updated = True
145-
146-
# todo needs to be done on _add_table / add_table
147-
df = csv_to_dataframe(web_data_dir / 'dG.csv')
148-
df.columns = fix_multiindex_dtypes(df.columns)
149-
src.add_table('dG', df)
150-
151-
#src.param.trigger('updated')
152-
src.updated = True
138+
# df = csv_to_dataframe(web_data_dir / 'd_uptake.csv')
139+
# df.columns = fix_multiindex_dtypes(df.columns)
140+
# src.add_table('d_uptake', df)
141+
# src.updated = True
142+
#
143+
# df = csv_to_dataframe(web_data_dir / 'dG.csv')
144+
# df.columns = fix_multiindex_dtypes(df.columns)
145+
# src.add_table('dG', df)
146+
147+
# src.updated = True
153148

154149

155150
# guess_control = ctrl.control_panels['InitialGuessControl']

pyhdx/web/apps/pyhdx_app.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ sources:
1010
type: pyhdx
1111
pdb:
1212
type: pdb
13+
metadata:
14+
type: dict
1315

1416
transforms:
1517
peptide_src:

pyhdx/web/apps/rfu_app.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ sources:
1010
type: pyhdx
1111
pdb:
1212
type: pdb
13+
metadata:
14+
type: dict
1315

1416
transforms:
1517
peptide_src:

pyhdx/web/controllers.py

Lines changed: 145 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import sys
55
import uuid
66
import zipfile
7-
from datetime import datetime
87
from io import StringIO, BytesIO
98
from typing import Any
109

@@ -195,8 +194,9 @@ def _action_debug(self):
195194
print(df_rfu)
196195

197196
def _action_test(self):
198-
pdbe_view = self.views["protein"]
199-
pdbe_view.pdbe.test = not pdbe_view.pdbe.test
197+
src = self.sources['metadata']
198+
d = src.get('user_settings')
199+
print(d)
200200

201201
@property
202202
def _layout(self):
@@ -265,7 +265,7 @@ def make_dict(self):
265265

266266
def config_download_callback(self) -> StringIO:
267267
# Generate and set filename
268-
timestamp = datetime.now().strftime("%Y%m%d%H%M")
268+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
269269
self.widgets[
270270
"config_download"
271271
].filename = f"PyHDX_config_{timestamp}.yaml"
@@ -400,15 +400,12 @@ def _action_load_datasets(self) -> None:
400400
)
401401

402402
def spec_download_callback(self) -> StringIO:
403-
timestamp = datetime.now().strftime("%Y%m%d%H%M")
403+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
404404
self.widgets[
405405
"download_spec_button"
406406
].filename = f"PyHDX_state_spec_{timestamp}.yaml"
407407

408-
s = yaml.dump(clean_types(self.state_spec), sort_keys=False)
409-
output = "# " + pyhdx.VERSION_STRING + "\n" + s
410-
sio = StringIO(output)
411-
408+
sio = self.parent.state_spec_callback()
412409
return sio
413410

414411
@property
@@ -1119,8 +1116,19 @@ def _action_fit(self):
11191116
self.param["do_fit"].constant = True
11201117
self.widgets["do_fit"].loading = True
11211118

1119+
user_dict = self.sources['metadata'].get('user_settings')
1120+
user_dict['d_uptake_fit'][self.fit_name] = self.get_user_settings()
11221121
async_execute(self._fit_d_uptake)
11231122

1123+
def get_user_settings(self) -> dict:
1124+
"""
1125+
Returns a dictionary with the current user settings.
1126+
"""
1127+
keys = ['bounds', 'r1']
1128+
d = {k: getattr(self, k) for k in keys}
1129+
1130+
return d
1131+
11241132
async def _fit_d_uptake(self):
11251133

11261134
name = self.fit_name
@@ -1276,7 +1284,9 @@ def _action_fit(self):
12761284
self.param["do_fit1"].constant = True
12771285
self.widgets["do_fit1"].loading = True
12781286

1279-
num_samples = len(self.src.hdxm_objects)
1287+
user_dict = self.sources['metadata'].get('user_settings')
1288+
user_dict['initial_guess'][self.guess_name] = self.get_user_settings()
1289+
12801290
if self.fitting_model.lower() in ["association", "dissociation"]:
12811291
loop = asyncio.get_running_loop()
12821292
loop.create_task(self._fit_rates(self.guess_name))
@@ -1322,6 +1332,21 @@ async def _fit_rates(self, name):
13221332
self.widgets["do_fit1"].loading = False
13231333
self.parent.logger.info(f"Finished initial guess fit {name}")
13241334

1335+
def get_user_settings(self) -> dict:
1336+
"""
1337+
Returns a dictionary with the current user settings.
1338+
"""
1339+
1340+
d = {'fitting_model': self.fitting_model}
1341+
if self.fitting_model in ["association", "dissociation"]:
1342+
d['global_bounds'] = self.global_bounds
1343+
if self.global_bounds:
1344+
d["bounds"] = [self.lower_bound, self.upper_bound]
1345+
else:
1346+
d["bounds"] = self.bounds
1347+
1348+
return d
1349+
13251350

13261351
class FitControl(PyHDXControlPanel):
13271352
"""
@@ -1481,6 +1506,9 @@ def _action_fit(self):
14811506
self._fit_names.append(self.fit_name)
14821507
self.parent.logger.info("Started PyTorch fit")
14831508

1509+
user_dict = self.sources['metadata'].get('user_settings')
1510+
user_dict['dG_fit'][self.fit_name] = self.get_user_settings()
1511+
14841512
self._current_jobs += 1
14851513
# if self._current_jobs >= self._max_jobs:
14861514
# self.widgets['do_fit'].constant = True
@@ -1600,6 +1628,24 @@ def fit_kwargs(self):
16001628

16011629
return fit_kwargs
16021630

1631+
def get_user_settings(self) -> dict:
1632+
"""
1633+
Returns a dictionary with the current user settings.
1634+
"""
1635+
1636+
d = {
1637+
'initial_guess': self.initial_guess,
1638+
'guess_mode': self.guess_mode
1639+
}
1640+
1641+
if self.guess_mode == 'One-to-many':
1642+
d['guess_state'] = self.guess_state
1643+
d['fit_mode'] = self.fit_mode
1644+
1645+
d.update(self.fit_kwargs)
1646+
1647+
return d
1648+
16031649

16041650
class DifferentialControl(PyHDXControlPanel):
16051651
_type = "diff"
@@ -1660,6 +1706,9 @@ def _action_add_comparison(self):
16601706
)
16611707
return
16621708

1709+
user_dict = self.sources['metadata'].get('user_settings')
1710+
user_dict['differential_HDX'][self.comparison_name] = self.get_user_settings()
1711+
16631712
# RFU only app has no dGs,
16641713
if "ddG_fit_select" in self.transforms:
16651714
self.add_ddG_comparison()
@@ -1790,6 +1839,14 @@ def add_dd_uptake_comparison(self):
17901839

17911840
self.src._add_table(dd_uptake, "dd_uptake")
17921841

1842+
def get_user_settings(self) -> dict:
1843+
"""
1844+
Returns a dictionary with the current user settings.
1845+
"""
1846+
1847+
d = {'reference_state': self.reference_state}
1848+
1849+
return d
17931850

17941851
class ColorTransformControl(PyHDXControlPanel):
17951852
"""
@@ -2430,12 +2487,39 @@ def make_dict(self):
24302487
callback=self.color_export_callback,
24312488
)
24322489

2490+
widgets["divider"] = pn.layout.Divider()
2491+
2492+
widgets["download_state_spec"] = pn.widgets.FileDownload(
2493+
label="Download HDX spec",
2494+
callback=self.state_spec_callback,
2495+
)
2496+
2497+
widgets["download_config"] = pn.widgets.FileDownload(
2498+
label="Download config",
2499+
callback=self.config_callback,
2500+
)
2501+
2502+
widgets["download_user_settings"] = pn.widgets.FileDownload(
2503+
label="Download user settings",
2504+
callback=self.user_settings_callback,
2505+
)
2506+
2507+
widgets["download_log"] = pn.widgets.FileDownload(
2508+
label="Download log",
2509+
callback = self.log_callback,
2510+
)
2511+
24332512
widget_order = [
24342513
"table",
24352514
"export_format",
24362515
"export_tables",
24372516
"export_pml",
24382517
"export_colors",
2518+
"divider",
2519+
"download_state_spec",
2520+
"download_config",
2521+
"download_user_settings",
2522+
"download_log",
24392523
]
24402524
final_widgets = {w: widgets[w] for w in widget_order}
24412525

@@ -2521,6 +2605,42 @@ def color_export_callback(self):
25212605
else:
25222606
return None
25232607

2608+
def state_spec_callback(self) -> StringIO:
2609+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
2610+
self.widgets[
2611+
"download_state_spec"
2612+
].filename = f"PyHDX_state_spec_{timestamp}.yaml"
2613+
2614+
sio = self.parent.state_spec_callback()
2615+
return sio
2616+
2617+
def config_callback(self) -> StringIO:
2618+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
2619+
self.widgets[
2620+
"download_config"
2621+
].filename = f"PyHDX_config_{timestamp}.yaml"
2622+
2623+
sio = self.parent.config_callback()
2624+
return sio
2625+
2626+
def user_settings_callback(self) -> StringIO:
2627+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
2628+
self.widgets[
2629+
"download_user_settings"
2630+
].filename = f"PyHDX_config_{timestamp}.yaml"
2631+
2632+
sio = self.parent.user_settings_callback()
2633+
return sio
2634+
2635+
def log_callback(self) -> StringIO:
2636+
timestamp = self.parent.session_time.strftime("%Y%m%d%H%M")
2637+
self.widgets[
2638+
"download_log"
2639+
].filename = f"PyHDX_log_{timestamp}.txt"
2640+
2641+
sio = self.parent.log_callback()
2642+
return sio
2643+
25242644

25252645
class FigureExportControl(PyHDXControlPanel):
25262646

@@ -2805,30 +2925,30 @@ def make_dict(self):
28052925
return widgets
28062926

28072927
def export_session_callback(self):
2808-
dt = datetime.today().strftime("%Y%m%d_%H%M")
2809-
self.widgets["export_session"].filename = f"{dt}_PyHDX_session.zip"
2928+
self.widgets["export_session"].filename = f"{self.parent.session_time.strftime('%Y%m%d_%H%M')}_PyHDX_session.zip"
28102929
bio = BytesIO()
28112930
with zipfile.ZipFile(bio, "w") as session_zip:
28122931
# Write tables
28132932
for name, table in self.sources["main"].tables.items():
28142933
sio = dataframe_to_stringio(table)
28152934
session_zip.writestr(name + ".csv", sio.getvalue())
28162935

2817-
# Write config file
2818-
masked_conf = OmegaConf.masked_copy(cfg.conf, cfg.conf.keys() - {'server'})
2819-
s = OmegaConf.to_yaml(masked_conf)
2820-
2821-
version_string = "# pyhdx configuration file " + __version__ + "\n\n"
2822-
session_zip.writestr("PyHDX_config.yaml", version_string + s)
2823-
2824-
# Write state spec file
2825-
input_controllers = {"PeptideFileInputControl", "PeptideRFUFileInputControl"}
2826-
input_ctrls = self.parent.control_panels.keys() & input_controllers
2827-
if len(input_ctrls) == 1:
2828-
input_ctrl = self.parent.control_panels[list(input_ctrls)[0]]
2829-
sio = input_ctrl.spec_download_callback()
2936+
# Write HDX measurement state specifications
2937+
if sio := self.parent.state_spec_callback():
28302938
session_zip.writestr("PyHDX_state_spec.yaml", sio.read())
28312939

2940+
# Write config file
2941+
sio = self.parent.config_callback()
2942+
session_zip.writestr("PyHDX_config.yaml", sio.read())
2943+
2944+
# Write user settings
2945+
sio = self.parent.user_settings_callback()
2946+
session_zip.writestr("PyHDX_user_settings.yaml", sio.read())
2947+
2948+
# Write log file
2949+
sio = self.parent.log_callback()
2950+
session_zip.writestr("PyHDX_log.txt", sio.read())
2951+
28322952
bio.seek(0)
28332953
return bio
28342954

0 commit comments

Comments
 (0)