bindmc 0.1.3__tar.gz → 0.1.5__tar.gz
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.
- {bindmc-0.1.3 → bindmc-0.1.5}/PKG-INFO +3 -3
- {bindmc-0.1.3 → bindmc-0.1.5}/pyproject.toml +3 -3
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/__main__.py +1 -1
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/main.py +2 -2
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/bayes.py +7 -2
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/data_import.py +1 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/data_model.py +6 -2
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/fitting.py +7 -8
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/state/statemanager.py +10 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/README.md +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/Class model.md +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/TODO.md +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/TODO_old.md +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/app.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/BindingConstant.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/ChemicalShiftParam.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/Component.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/ExptData.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/ExptDataType.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/FitResult.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/MCMCSim.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/Model.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/RawData.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/Simulation.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/UIBindings.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/classes/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/base.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/bayes_priors.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/binding_model.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/body.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/data_gen.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/graph.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/header.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/components/simulation.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/default_models.json +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/export/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/export/notebook_exporter.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/state/__init__.py +0 -0
- {bindmc-0.1.3 → bindmc-0.1.5}/src/bindmc/webgui/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: bindmc
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Keywords: chemistry,analytical chemistry,binding constants,supramolecular
|
|
5
5
|
Author: Martin Peeks
|
|
6
6
|
Author-email: Martin Peeks <martinp23@googlemail.com>, m.peeks@unsw.edu.au
|
|
@@ -12,10 +12,10 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
12
12
|
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
13
13
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
14
14
|
Requires-Dist: arviz==0.21.0
|
|
15
|
-
Requires-Dist: bindtools>=0.1.
|
|
15
|
+
Requires-Dist: bindtools>=0.1.3
|
|
16
16
|
Requires-Dist: corner==2.2.3
|
|
17
17
|
Requires-Dist: emcee==3.1.6
|
|
18
|
-
Requires-Dist: h5py
|
|
18
|
+
Requires-Dist: h5py>=3.14.0
|
|
19
19
|
Requires-Dist: latex2mathml>=3.0.0
|
|
20
20
|
Requires-Dist: lmfit==1.3.3
|
|
21
21
|
Requires-Dist: matplotlib==3.10.7
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "bindmc"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.5"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
keywords = ["chemistry", "analytical chemistry", "binding constants", "supramolecular"]
|
|
10
10
|
classifiers = [
|
|
@@ -28,10 +28,10 @@ classifiers = [
|
|
|
28
28
|
requires-python = ">=3.12"
|
|
29
29
|
dependencies = [
|
|
30
30
|
"arviz==0.21.0",
|
|
31
|
-
"bindtools>=0.1.
|
|
31
|
+
"bindtools>=0.1.3",
|
|
32
32
|
"corner==2.2.3",
|
|
33
33
|
"emcee==3.1.6",
|
|
34
|
-
"h5py
|
|
34
|
+
"h5py>=3.14.0",
|
|
35
35
|
"latex2mathml>=3.0.0",
|
|
36
36
|
"lmfit==1.3.3",
|
|
37
37
|
"matplotlib==3.10.7",
|
|
@@ -107,7 +107,7 @@ storage_path.mkdir(parents=True, exist_ok=True)
|
|
|
107
107
|
# Redirect native window persistence data away from default paths
|
|
108
108
|
app.native.start_args["storage_path"] = str(storage_path)
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
ui.run(title="BindMC", reload=reload, native=native_mode, port=native.find_open_port(), storage_secret="bindmc_secret")
|
|
110
|
+
if __name__ in {"__main__", "__mp_main__"}:
|
|
111
|
+
ui.run(title="BindMC", reload=reload, native=native_mode, port=native.find_open_port(), storage_secret="bindmc_secret")
|
|
112
112
|
|
|
113
113
|
|
|
@@ -245,7 +245,7 @@ class BayesPanel(BaseComponent):
|
|
|
245
245
|
return
|
|
246
246
|
|
|
247
247
|
if active_fit.bd_model is None:
|
|
248
|
-
|
|
248
|
+
logger.info("No bindtools model selected for fitting, generating one.")
|
|
249
249
|
ui.notify("Running an initial fit using least_sq")
|
|
250
250
|
m1 = self.sm.generate_binding_model_for_fit(active_fit)
|
|
251
251
|
m1 = await run.cpu_bound(
|
|
@@ -262,6 +262,7 @@ class BayesPanel(BaseComponent):
|
|
|
262
262
|
nwalkers = int(self.nwalkers_input.value)
|
|
263
263
|
obslist = self.sm.active_expt_data.get_obs_list(self.sm._expt_dtypes)
|
|
264
264
|
|
|
265
|
+
logger.info("Setting up for MCMC run")
|
|
265
266
|
# Create MCMC simulation (not yet registered in state)
|
|
266
267
|
self.mcmc = MCMCSim(
|
|
267
268
|
model=self.sm.active_model,
|
|
@@ -281,12 +282,13 @@ class BayesPanel(BaseComponent):
|
|
|
281
282
|
type="info",
|
|
282
283
|
timeout=60000,
|
|
283
284
|
)
|
|
285
|
+
logger.info("Running a trial run")
|
|
284
286
|
try:
|
|
285
287
|
trial_elapsed = await run.cpu_bound(partial(_run_mcmc_trial, self.mcmc.mc, _TRIAL_STEPS))
|
|
286
288
|
it_s = _TRIAL_STEPS / trial_elapsed
|
|
287
289
|
full_seconds = nsteps_target * trial_elapsed / _TRIAL_STEPS
|
|
288
290
|
full_time_str = _format_duration(full_seconds)
|
|
289
|
-
|
|
291
|
+
logger.info("Trial run finished; took {trial_elapsed:.1f} s ({it_s:.2f} it/s).")
|
|
290
292
|
with ui.dialog() as timing_dialog, ui.card().classes("w-[min(560px,92vw)]"):
|
|
291
293
|
ui.label("Runtime estimate").classes("text-lg font-bold")
|
|
292
294
|
ui.label(f"{_TRIAL_STEPS:,} steps took {trial_elapsed:.1f} s ({it_s:.2f} it/s).").classes(
|
|
@@ -296,6 +298,8 @@ class BayesPanel(BaseComponent):
|
|
|
296
298
|
f"The full run ({nsteps_target:,} steps, {nwalkers} walkers) "
|
|
297
299
|
f"will take approximately {full_time_str}."
|
|
298
300
|
).classes("mt-2")
|
|
301
|
+
logger.info(f"The full run ({nsteps_target:,} steps, {nwalkers} walkers) "
|
|
302
|
+
f"will take approximately {full_time_str}.")
|
|
299
303
|
ui.label("Do you want to continue?").classes("mt-1 font-medium")
|
|
300
304
|
with ui.row().classes("w-full justify-end gap-2 mt-3"):
|
|
301
305
|
ui.button("Cancel", on_click=lambda: timing_dialog.submit(False))
|
|
@@ -320,6 +324,7 @@ class BayesPanel(BaseComponent):
|
|
|
320
324
|
self.run_button.set_enabled(False)
|
|
321
325
|
self.stop_button.set_enabled(True)
|
|
322
326
|
self.progress_bar.value = 0
|
|
327
|
+
logger.info("Starting MCMC analysis")
|
|
323
328
|
self.progress_label.text = "Starting MCMC analysis..."
|
|
324
329
|
self._log_status("Starting MCMC analysis...")
|
|
325
330
|
self._start_run_timers()
|
|
@@ -126,6 +126,7 @@ class DataImportPanel(BaseComponent):
|
|
|
126
126
|
rd = active_raw
|
|
127
127
|
new_expt_data = ExptData(name=rd.filename, init_raw_data=rd, init_model=self.sm.active_model)
|
|
128
128
|
self.sm.add_expt_data(new_expt_data)
|
|
129
|
+
self.sm.notify_listeners("data_imported") # Trigger table and graph update
|
|
129
130
|
else:
|
|
130
131
|
ui.notify("No raw data selected to prepare data model from.", type="negative")
|
|
131
132
|
|
|
@@ -65,6 +65,10 @@ class DataModelPanel(BaseComponent):
|
|
|
65
65
|
|
|
66
66
|
nmr_fast_ex = False
|
|
67
67
|
nmr_slow_ex = False
|
|
68
|
+
|
|
69
|
+
# make all visible to allow changes in the next code block before we hide them again if not needed
|
|
70
|
+
self.dataModel_specInteg_block.visible = True
|
|
71
|
+
self.dataModel_specFastExchange_block.visible = True
|
|
68
72
|
|
|
69
73
|
# work out what we need
|
|
70
74
|
if self.sm.active_expt_data_or_none is not None:
|
|
@@ -76,7 +80,7 @@ class DataModelPanel(BaseComponent):
|
|
|
76
80
|
if getattr(dtype, "meas", None) == "nmr_ppm" and f.get("depindep") == "dep":
|
|
77
81
|
nmr_fast_ex = True
|
|
78
82
|
self._gen_spec_fast_exchange_block()
|
|
79
|
-
elif getattr(dtype, "meas", None) == "
|
|
83
|
+
elif getattr(dtype, "meas", None) == "nmr_integ" and f.get("depindep") == "dep":
|
|
80
84
|
nmr_slow_ex = True
|
|
81
85
|
self._gen_spec_integ_block()
|
|
82
86
|
|
|
@@ -142,7 +146,7 @@ class DataModelPanel(BaseComponent):
|
|
|
142
146
|
self.spec_integ_inps[spec] = ui.input().classes("flex-1").props("clearable")
|
|
143
147
|
|
|
144
148
|
self.spec_integ_inps[spec].on("blur", lambda c=self.spec_integ_inps[spec]: self.set_focus(c))
|
|
145
|
-
b = ui.checkbox("Enabled", value=True)
|
|
149
|
+
b = ui.checkbox("Enabled", value=True).props(f"testid=spec-enabled-{spec}")
|
|
146
150
|
self.spec_integ_inps[spec].bind_enabled_from(b, "value")
|
|
147
151
|
if (
|
|
148
152
|
hasattr(active_expt, "integ_to_spec")
|
|
@@ -108,7 +108,7 @@ def _infer_analytical_fast_exchange_config(model, expt_data, expt_dtypes: dict)
|
|
|
108
108
|
has_nmr = True
|
|
109
109
|
elif meas in ("uvvis", "fluorescence"):
|
|
110
110
|
has_linear = True
|
|
111
|
-
else:
|
|
111
|
+
else:
|
|
112
112
|
return None # Unknown or unsupported observable type for analytical path
|
|
113
113
|
|
|
114
114
|
if has_nmr and has_linear:
|
|
@@ -442,6 +442,9 @@ class FittingPanel(BaseComponent):
|
|
|
442
442
|
self.sm.active_expt_data,
|
|
443
443
|
self.sm._expt_dtypes,
|
|
444
444
|
)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
445
448
|
self.m1 = self.sm.generate_binding_model_for_fit(analytical_cfg=analytical_cfg)
|
|
446
449
|
if analytical_cfg is not None:
|
|
447
450
|
ui.notify(
|
|
@@ -492,7 +495,7 @@ class FittingPanel(BaseComponent):
|
|
|
492
495
|
init_model=self.sm.active_model,
|
|
493
496
|
bd_model=self.m1,
|
|
494
497
|
analytical_fast_exchange=analytical_cfg is not None,
|
|
495
|
-
analytical_topology=
|
|
498
|
+
analytical_topology=self.m1.analytical_topology,
|
|
496
499
|
analytical_obs_columns=(
|
|
497
500
|
[str(x) for x in cast(list[str], analytical_cfg["obs_columns"])]
|
|
498
501
|
if analytical_cfg is not None
|
|
@@ -503,11 +506,7 @@ class FittingPanel(BaseComponent):
|
|
|
503
506
|
if analytical_cfg is not None
|
|
504
507
|
else []
|
|
505
508
|
),
|
|
506
|
-
analytical_complex_indices=
|
|
507
|
-
[int(x) for x in cast(list[int], analytical_cfg["complex_indices"])]
|
|
508
|
-
if analytical_cfg is not None
|
|
509
|
-
else []
|
|
510
|
-
),
|
|
509
|
+
analytical_complex_indices=self.m1.analytical_complex_indices,
|
|
511
510
|
)
|
|
512
511
|
self.sm.add_fit(new_fit)
|
|
513
512
|
|
|
@@ -536,7 +535,7 @@ class FittingPanel(BaseComponent):
|
|
|
536
535
|
|
|
537
536
|
def _update_fit_graphs(self, e=None) -> None:
|
|
538
537
|
"""Update the fit results display."""
|
|
539
|
-
|
|
538
|
+
logger.info("Updating fit results...")
|
|
540
539
|
self.fit_graph.clear_graph(update=False)
|
|
541
540
|
if len(self.sm.fits) > 0:
|
|
542
541
|
self.speciation_graph.clear_graph(update=False)
|
|
@@ -1777,6 +1777,16 @@ bd.makeFitResidPlot(fit,plotMask=(0,1),ylabel='Chemical shift (ppm)')"""
|
|
|
1777
1777
|
model.analytical_linear_obs_columns = lin_cols
|
|
1778
1778
|
model.analytical_linear_obs_param_map = linear_obs_param_map
|
|
1779
1779
|
|
|
1780
|
+
# Always infer topology to allow analytical concentrations in slow exchange
|
|
1781
|
+
from bindmc.webgui.utils import _infer_simple_fast_exchange_topology
|
|
1782
|
+
topology_res = _infer_simple_fast_exchange_topology(
|
|
1783
|
+
self.active_model.eq_mat, len(self.active_model.component_names)
|
|
1784
|
+
)
|
|
1785
|
+
if topology_res is not None:
|
|
1786
|
+
topo_name, complex_indices = topology_res
|
|
1787
|
+
model.analytical_topology = topo_name
|
|
1788
|
+
model.analytical_complex_indices = complex_indices
|
|
1789
|
+
|
|
1780
1790
|
model.prepModel()
|
|
1781
1791
|
|
|
1782
1792
|
for k in self.active_model.binding_constants:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|