bindmc 0.1.0__tar.gz → 0.1.2__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.
Files changed (68) hide show
  1. bindmc-0.1.2/PKG-INFO +63 -0
  2. bindmc-0.1.2/README.md +25 -0
  3. {bindmc-0.1.0 → bindmc-0.1.2}/pyproject.toml +39 -1
  4. bindmc-0.1.2/src/bindmc/main.py +72 -0
  5. bindmc-0.1.2/src/bindmc/webgui/Class model.md +27 -0
  6. bindmc-0.1.2/src/bindmc/webgui/TODO.md +232 -0
  7. bindmc-0.1.2/src/bindmc/webgui/TODO_old.md +89 -0
  8. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/app.py +13 -17
  9. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/BindingConstant.py +3 -10
  10. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/ChemicalShiftParam.py +9 -15
  11. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/Component.py +9 -25
  12. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/ExptData.py +76 -72
  13. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/ExptDataType.py +18 -25
  14. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/FitResult.py +31 -44
  15. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/MCMCSim.py +22 -37
  16. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/Model.py +10 -26
  17. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/RawData.py +4 -16
  18. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/Simulation.py +13 -34
  19. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/UIBindings.py +3 -8
  20. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/classes/__init__.py +2 -3
  21. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/__init__.py +2 -2
  22. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/base.py +1 -0
  23. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/bayes.py +194 -195
  24. bindmc-0.1.2/src/bindmc/webgui/components/bayes_priors.py +368 -0
  25. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/binding_model.py +86 -89
  26. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/body.py +31 -54
  27. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/data_gen.py +59 -78
  28. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/data_import.py +159 -150
  29. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/data_model.py +171 -163
  30. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/fitting.py +152 -157
  31. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/graph.py +133 -137
  32. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/header.py +22 -22
  33. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/components/simulation.py +42 -69
  34. bindmc-0.1.2/src/bindmc/webgui/default_models.json +1 -0
  35. bindmc-0.1.2/src/bindmc/webgui/export/__init__.py +0 -0
  36. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/export/notebook_exporter.py +230 -213
  37. bindmc-0.1.2/src/bindmc/webgui/state/__init__.py +1 -0
  38. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/state/statemanager.py +293 -375
  39. {bindmc-0.1.0 → bindmc-0.1.2}/src/bindmc/webgui/utils.py +64 -58
  40. bindmc-0.1.0/PKG-INFO +0 -22
  41. bindmc-0.1.0/setup.cfg +0 -4
  42. bindmc-0.1.0/src/bindmc/main.py +0 -67
  43. bindmc-0.1.0/src/bindmc/webgui/components/bayes_priors.py +0 -351
  44. bindmc-0.1.0/src/bindmc/webgui/state/__init__.py +0 -1
  45. bindmc-0.1.0/src/bindmc.egg-info/PKG-INFO +0 -22
  46. bindmc-0.1.0/src/bindmc.egg-info/SOURCES.txt +0 -56
  47. bindmc-0.1.0/src/bindmc.egg-info/dependency_links.txt +0 -1
  48. bindmc-0.1.0/src/bindmc.egg-info/requires.txt +0 -18
  49. bindmc-0.1.0/src/bindmc.egg-info/top_level.txt +0 -1
  50. bindmc-0.1.0/tests/test_active_context_state_manager.py +0 -245
  51. bindmc-0.1.0/tests/test_analytical_fast_exchange_backend.py +0 -203
  52. bindmc-0.1.0/tests/test_bayes_plot_sizing.py +0 -31
  53. bindmc-0.1.0/tests/test_body_tab_guidance.py +0 -101
  54. bindmc-0.1.0/tests/test_component_concentration.py +0 -87
  55. bindmc-0.1.0/tests/test_data_model_analytical_defaults.py +0 -19
  56. bindmc-0.1.0/tests/test_exptdata_shift_param_naming.py +0 -104
  57. bindmc-0.1.0/tests/test_fit_analytical_fast_exchange_screen.py +0 -167
  58. bindmc-0.1.0/tests/test_fit_graph_subset_dep_vars.py +0 -137
  59. bindmc-0.1.0/tests/test_model_setups.py +0 -165
  60. bindmc-0.1.0/tests/test_model_to_python.py +0 -22
  61. bindmc-0.1.0/tests/test_notebook_export.py +0 -548
  62. bindmc-0.1.0/tests/test_sim_flow.py +0 -59
  63. bindmc-0.1.0/tests/test_simulation_workflow_screen.py +0 -144
  64. bindmc-0.1.0/tests/test_startup.py +0 -17
  65. bindmc-0.1.0/tests/test_uvvis_fluorescence.py +0 -520
  66. bindmc-0.1.0/tests/testutils.py +0 -15
  67. {bindmc-0.1.0/src/bindmc/webgui → bindmc-0.1.2/src/bindmc}/__init__.py +0 -0
  68. {bindmc-0.1.0/src/bindmc/webgui/export → bindmc-0.1.2/src/bindmc/webgui}/__init__.py +0 -0
bindmc-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.3
2
+ Name: bindmc
3
+ Version: 0.1.2
4
+ Keywords: chemistry,analytical chemistry,binding constants,supramolecular
5
+ Author: Martin Peeks
6
+ Author-email: Martin Peeks <martinp23@googlemail.com>, m.peeks@unsw.edu.au
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
13
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
14
+ Requires-Dist: arviz==0.21.0
15
+ Requires-Dist: bindtools>=0.1.0
16
+ Requires-Dist: corner==2.2.3
17
+ Requires-Dist: emcee==3.1.6
18
+ Requires-Dist: h5py==3.13.0
19
+ Requires-Dist: latex2mathml>=3.0.0
20
+ Requires-Dist: lmfit==1.3.3
21
+ Requires-Dist: matplotlib==3.10.7
22
+ Requires-Dist: nicegui[plotly]==3.3.1
23
+ Requires-Dist: numba>=0.65.1
24
+ Requires-Dist: numpy>=2.3.5
25
+ Requires-Dist: openpyxl==3.1.2
26
+ Requires-Dist: pandas>=2.3.3
27
+ Requires-Dist: platformdirs>=3.0.0
28
+ Requires-Dist: pywebview>=5
29
+ Requires-Dist: scipy==1.16.3
30
+ Requires-Dist: tqdm==4.66.3
31
+ Requires-Dist: uncertainties==3.2.3
32
+ Requires-Python: >=3.12
33
+ Project-URL: Homepage, https://github.com/martinp23/bindmc
34
+ Project-URL: Documentation, https://readthedocs.org
35
+ Project-URL: Repository, https://github.com/martinp23/bindmc.git
36
+ Project-URL: Issues, https://github.com/martinp23/bindmc/issues
37
+ Description-Content-Type: text/markdown
38
+
39
+ # bindmc
40
+
41
+ [![PyPI version](https://badge.fury.io/py/bindtools.svg)](https://badge.fury.io/py/bindtools)
42
+ [![Python Version](https://img.shields.io/pypi/pyversions/bindtools.svg)](https://pypi.org/project/bindtools/)
43
+
44
+ `bindmc` is a tool for calculating binding constants, built on top of [bindtools](https://github.com/martinp23/bindtools).
45
+
46
+ ## Installation
47
+
48
+ ### Pre-built Binary
49
+ Download the latest executable for your platform from the [Releases](https://github.com/martinp23/bindmc/releases) page.
50
+
51
+ ### Pip
52
+ ```bash
53
+ pip install bindmc
54
+ ```
55
+
56
+ ## Usage
57
+
58
+ If using the pre-built binary, run the downloaded executable.
59
+
60
+ If installed via pip, run:
61
+ ```bash
62
+ python -m bindmc
63
+ ```
bindmc-0.1.2/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # bindmc
2
+
3
+ [![PyPI version](https://badge.fury.io/py/bindtools.svg)](https://badge.fury.io/py/bindtools)
4
+ [![Python Version](https://img.shields.io/pypi/pyversions/bindtools.svg)](https://pypi.org/project/bindtools/)
5
+
6
+ `bindmc` is a tool for calculating binding constants, built on top of [bindtools](https://github.com/martinp23/bindtools).
7
+
8
+ ## Installation
9
+
10
+ ### Pre-built Binary
11
+ Download the latest executable for your platform from the [Releases](https://github.com/martinp23/bindmc/releases) page.
12
+
13
+ ### Pip
14
+ ```bash
15
+ pip install bindmc
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ If using the pre-built binary, run the downloaded executable.
21
+
22
+ If installed via pip, run:
23
+ ```bash
24
+ python -m bindmc
25
+ ```
@@ -1,6 +1,30 @@
1
+ [build-system]
2
+ requires = ["uv_build"]
3
+ build-backend = "uv_build"
4
+
1
5
  [project]
2
6
  name = "bindmc"
3
- version = "0.1.0"
7
+ version = "0.1.2"
8
+ readme = "README.md"
9
+ keywords = ["chemistry", "analytical chemistry", "binding constants", "supramolecular"]
10
+ classifiers = [
11
+ # How mature is this project? Common values are
12
+ # 3 - Alpha
13
+ # 4 - Beta
14
+ # 5 - Production/Stable
15
+ "Development Status :: 3 - Alpha",
16
+
17
+ # Indicate who your project is intended for
18
+ "Intended Audience :: Science/Research",
19
+
20
+ # Specify the Python versions you support here.
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+
25
+ "Topic :: Scientific/Engineering :: Chemistry",
26
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
27
+ ]
4
28
  requires-python = ">=3.12"
5
29
  dependencies = [
6
30
  "arviz==0.21.0",
@@ -23,6 +47,17 @@ dependencies = [
23
47
  "uncertainties==3.2.3",
24
48
  ]
25
49
 
50
+ authors = [
51
+ {name = "Martin Peeks", email = "martinp23@googlemail.com"},
52
+ {email = "m.peeks@unsw.edu.au"},
53
+ ]
54
+
55
+ [project.urls]
56
+ Homepage = "https://github.com/martinp23/bindmc"
57
+ Documentation = "https://readthedocs.org"
58
+ Repository = "https://github.com/martinp23/bindmc.git"
59
+ Issues = "https://github.com/martinp23/bindmc/issues"
60
+
26
61
  [tool.uv.sources]
27
62
  bindtools = { path = "./bindtools", editable = true }
28
63
 
@@ -107,4 +142,7 @@ docstring-code-line-length = "dynamic"
107
142
  dev = [
108
143
  "pyinstaller>=6.21.0",
109
144
  "pytest>=9.1.0",
145
+ "pytest-asyncio>=1.4.0",
146
+ "ruff>=0.15.17",
147
+ "selenium>=4.44.0",
110
148
  ]
@@ -0,0 +1,72 @@
1
+ # to build: rm -fr build && rm -fr dist && nicegui-pack --onefile --add-data "C:\Users\mpeeks\miniforge3\envs\binding-nicegui\Lib\site-packages\arviz\static;arviz/static" --add-data "C:\Users\mpeeks\miniforge3\envs\binding-nicegui\Lib\site-packages\arviz\data;arviz/data" --add-data "C:\Users\mpeeks\miniforge3\envs\binding-nicegui\Lib\site-packages\latex2mathml\unimathsymbols.txt;latex2mathml" main.py
2
+
3
+ # on windows:
4
+ # nicegui-pack main.py --no-build
5
+
6
+ # macOS packaging support
7
+ from multiprocessing import freeze_support # noqa
8
+
9
+ freeze_support() # noqa
10
+
11
+ # hidden import for pyinstaller
12
+ import matplotlib
13
+
14
+ matplotlib.use("module://matplotlib.backends.backend_svg")
15
+ import sys
16
+ from nicegui import native, ui, app
17
+ from bindmc.webgui.app import BindMCServer
18
+ import logging
19
+ import nicegui
20
+ from packaging.version import InvalidVersion, Version
21
+ from pathlib import Path
22
+ from platformdirs import user_data_dir
23
+ from importlib.metadata import version
24
+
25
+ __version__ = version("bindmc")
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ try:
30
+ nicegui_version = Version(nicegui.__version__)
31
+ except InvalidVersion:
32
+ logger.warning(
33
+ "Could not parse NiceGUI version '%s'; continuing, but NiceGUI >= 3 is required.",
34
+ nicegui.__version__,
35
+ )
36
+ else:
37
+ if nicegui_version.is_prerelease or nicegui_version.is_devrelease:
38
+ logger.warning(
39
+ "NiceGUI %s is a pre-release/dev build; recommended to install the latest stable 3.x.",
40
+ nicegui.__version__,
41
+ )
42
+ elif nicegui_version.major < 3:
43
+ raise RuntimeError(f"NiceGUI >= 3 is required; found {nicegui.__version__}")
44
+
45
+
46
+ app.native.settings["ALLOW_DOWNLOADS"] = True
47
+
48
+ # logging.basicConfig(level=logging.INFO, filename='BindMC.log')
49
+ logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
50
+
51
+ logger.info(f"Starting BindMC {__version__} NiceGUI server...")
52
+ BindMCServer()
53
+
54
+ # Set DEV based on whether running from PyInstaller bundle
55
+ DEV = not getattr(sys, "frozen", False)
56
+
57
+ if DEV:
58
+ native_mode = False
59
+ reload = True
60
+ else:
61
+ native_mode = True
62
+ reload = False
63
+
64
+
65
+ # make a sensible storage path for native mode
66
+ storage_path = Path(user_data_dir(appname="BindMC", appauthor=False))
67
+ storage_path.mkdir(parents=True, exist_ok=True)
68
+
69
+ # Redirect native window persistence data away from default paths
70
+ app.native.start_args["storage_path"] = str(storage_path)
71
+
72
+ ui.run(title="BindMC", reload=reload, native=native_mode, port=native.find_open_port(), storage_secret="bindmc_secret")
@@ -0,0 +1,27 @@
1
+ Class model
2
+
3
+ - UIState
4
+ - This class contains the current state of the user interface, so includes:
5
+ - list of Models and index of active Model
6
+ - List of simulations and field values from latest/active simulation
7
+ - Graph state
8
+ - component details
9
+
10
+ - Simulation
11
+ - A simulation comprises:
12
+ - A Model
13
+ - A set of parameters
14
+ - Input data (i.e. components)
15
+ - Output data (i.e. species concentrations)
16
+ - A name or timestamp or other unique(?) slug
17
+ - An optional comment
18
+
19
+ - Model
20
+ - Comprises
21
+ - A name (unique among all models in the UIState)
22
+ - An optional comment
23
+ - The string entered into the eqStr input box
24
+ - The parsed equation matrix as a list of lists (np.array)
25
+ - (A function that returns a list of BindingConstant parameters?)
26
+ - A list of species
27
+ - A list of components
@@ -0,0 +1,232 @@
1
+ # BindMC WebGUI Release Checklist
2
+
3
+ Use this as the source of truth for shipping readiness.
4
+
5
+ Legend:
6
+ - `Priority`: `P0` (must ship), `P1` (should ship), `P2` (hardening)
7
+ - `Effort`: `S`, `M`, `L`
8
+ - `Owner`: set to initials or role (`@unassigned` until assigned)
9
+
10
+ ## P0 - Must Ship
11
+
12
+ - [ ] Streamline analytical methods in bindtools package binding.py
13
+
14
+ - Check obs_list is right in tests/elsewhere, and/or check "uvvis" vs "absorbance" dtype
15
+ - Add timing trial done/starting real run popups
16
+ - Dark species do not appear in fit and mcmc any mroe - check obslist change!
17
+ - [ ] Fix fit graph mismatch when only subset of dependent variables are fitted.
18
+ - Owner: `@unassigned`
19
+ - Effort: `M`
20
+ - Files: `webgui/components/fitting.py`, `webgui/components/graph.py`
21
+
22
+ - [X] Make active object handling robust after delete/change (model, data, fit, sim).
23
+ - Owner: `@unassigned`
24
+ - Effort: `M`
25
+ - Files: `webgui/state/statemanager.py`
26
+
27
+ - [ ] Implement explicit expt data load/select/delete workflow in UI.
28
+ - Owner: `@unassigned`
29
+ - Effort: `M`
30
+ - Files: `webgui/components/data_import.py`, `webgui/components/body.py`, `webgui/state/statemanager.py`
31
+
32
+ - [ ] Add strict validation + actionable inline errors for data-model mapping (col->comp, integ->spec, fast-exchange).
33
+ - Owner: `@unassigned`
34
+ - Effort: `L`
35
+ - Files: `webgui/components/data_model.py`, `webgui/classes/ExptData.py`
36
+
37
+ - [X] Sanitize chemical-shift parameter names (spaces/special chars) before lmfit parameter creation.
38
+ - Owner: `@unassigned`
39
+ - Effort: `S`
40
+ - Files: `webgui/classes/ExptData.py`
41
+
42
+ - [ ] Apply consistent long-task UI state handling (disable/re-enable buttons + spinner + no double-submit).
43
+ - Owner: `@unassigned`
44
+ - Effort: `M`
45
+ - Files: `webgui/components/simulation.py`, `webgui/components/fitting.py`, `webgui/components/data_import.py`
46
+
47
+ - [ ] Add destructive action confirmations and unsaved-change protection.
48
+ - Owner: `@unassigned`
49
+ - Effort: `M`
50
+ - Files: `webgui/components/header.py`, `webgui/state/statemanager.py`, relevant panel files
51
+
52
+ - [X] Fix disabled-tab guidance so reason is always visible and correct.
53
+ - Owner: `@unassigned`
54
+ - Effort: `S`
55
+ - Files: `webgui/components/body.py`
56
+
57
+ ## P1 - Should Ship
58
+
59
+ - [ ] UI polish pass (spacing, naming consistency, remove placeholder text, responsive fit/focus).
60
+ - Owner: `@unassigned`
61
+ - Effort: `M`
62
+ - Files: `webgui/components/*.py`
63
+
64
+ - [ ] Add raw-data quick plot/preview during import to validate selected columns.
65
+ - Owner: `@unassigned`
66
+ - Effort: `M`
67
+ - Files: `webgui/components/data_import.py`, `webgui/components/graph.py`
68
+
69
+ - [ ] Complete graph export UX (PNG options/resolution, fit/sim parity, clear labels).
70
+ - Owner: `@unassigned`
71
+ - Effort: `S`
72
+ - Files: `webgui/components/fitting.py`, `webgui/components/simulation.py`
73
+
74
+ - [ ] Persist graph view preferences (x-axis, ratio, legend visibility) across reload.
75
+ - Owner: `@unassigned`
76
+ - Effort: `M`
77
+ - Files: `webgui/components/graph.py`, `webgui/state/statemanager.py`
78
+
79
+ - [ ] Replace broad `except Exception` with specific exceptions + targeted user notifications.
80
+ - Owner: `@unassigned`
81
+ - Effort: `M`
82
+ - Files: multiple `webgui/components/*.py`, `webgui/state/statemanager.py`
83
+
84
+ - [ ] Replace remaining `print` calls with structured logging.
85
+ - Owner: `@unassigned`
86
+ - Effort: `S`
87
+ - Files: multiple `webgui/**/*.py`
88
+
89
+ - [ ] Improve first-run empty states and inline guidance for main workflows.
90
+ - Owner: `@unassigned`
91
+ - Effort: `M`
92
+ - Files: `webgui/components/body.py`, panel files
93
+
94
+ ## P2 - Hardening
95
+
96
+ - [ ] Add end-to-end test for fit workflow including CSV/PNG export.
97
+ - Owner: `@unassigned`
98
+ - Effort: `L`
99
+ - Files: `tests/`
100
+
101
+ - [ ] Add regression tests for cascade deletion and active-ID reassignment.
102
+ - Owner: `@unassigned`
103
+ - Effort: `M`
104
+ - Files: `tests/`, `webgui/state/statemanager.py`
105
+
106
+ - [ ] Add serialization round-trip tests for fast-exchange (`delta_to_spec`, `limiting_shifts`).
107
+ - Owner: `@unassigned`
108
+ - Effort: `M`
109
+ - Files: `tests/`, `webgui/classes/ExptData.py`
110
+
111
+ - [ ] Create packaging smoke-test checklist (platform launch, downloads, save/open, project import/export).
112
+ - Owner: `@unassigned`
113
+ - Effort: `S`
114
+ - Files: `docs/` (new release checklist doc)
115
+
116
+ - [ ] Add release process doc (version bump, changelog, sign-off criteria).
117
+ - Owner: `@unassigned`
118
+ - Effort: `S`
119
+ - Files: `docs/` (new release process doc)
120
+
121
+ ## Post-Ship Backlog
122
+
123
+ - [ ] Complete MCMC analysis workflow.
124
+ - Owner: `@unassigned`
125
+ - Effort: `L`
126
+
127
+ - [X] Add analytical-mode simulation support for simple 1:1/1:2/2:1 fast-exchange systems.
128
+ - Owner: `@unassigned`
129
+ - Effort: `M`
130
+ - Note: Until this ships, point users to supramolecular.org for these simulations.
131
+
132
+ - [ ] Add graph log-scale options and richer plot controls.
133
+ - Owner: `@unassigned`
134
+ - Effort: `M`
135
+
136
+ - [ ] Improve model comments/metadata editing UX.
137
+ - Owner: `@unassigned`
138
+ - Effort: `S`
139
+
140
+ ## Legacy Notes (Untriaged)
141
+
142
+ Carried forward from the previous TODO for reference:
143
+
144
+ - Enable choosing of graph elements:
145
+ - What should be y-axis? Plot all species ideally
146
+ - allow comments alongside equilibria
147
+ - graphs - y/x log options
148
+ - fast exchange work
149
+ - add refresh-bindings as in model tab to other tabs
150
+ - precompile numba (part done)
151
+
152
+ ## Sprint-Ready Breakdown (Top 3 P0)
153
+
154
+ ### A) Fix fit graph mismatch for partially fitted dependent variables
155
+
156
+ - [ ] A1. Reproduce and lock down failing scenario with test data containing multiple dependent columns where only a subset is fitted.
157
+ - Owner: `@unassigned`
158
+ - Effort: `S`
159
+
160
+ - [ ] A2. Ensure graph plotting uses only columns present in `fit.calc_obs` and aligned index lengths.
161
+ - Owner: `@unassigned`
162
+ - Effort: `S`
163
+ - Files: `webgui/components/fitting.py`, `webgui/components/graph.py`
164
+
165
+ - [ ] A3. Add guardrail notifications when expected columns are missing, without crashing render.
166
+ - Owner: `@unassigned`
167
+ - Effort: `S`
168
+ - Files: `webgui/components/fitting.py`
169
+
170
+ - [ ] A4. Add regression test for fit graph rendering with partial dependent-variable fitting.
171
+ - Owner: `@unassigned`
172
+ - Effort: `M`
173
+ - Files: `tests/`
174
+
175
+ Acceptance criteria:
176
+ - Fit results tab renders both experimental markers and calculated lines with no exceptions when only subset of dependent variables is fitted.
177
+ - No mismatch warnings/errors appear for valid partial-fit cases.
178
+ - Regression test fails on old behavior and passes on fix.
179
+
180
+ ### B) Make active-object handling robust after delete/change (model/data/fit/sim)
181
+
182
+ - [ ] B1. Audit all delete/change paths to identify where active IDs may become stale.
183
+ - Owner: `@unassigned`
184
+ - Effort: `S`
185
+ - Files: `webgui/state/statemanager.py`, `webgui/components/*.py`
186
+
187
+ - [ ] B2. Implement centralized helper(s) in `StateManager` to set safe fallback active IDs after deletion.
188
+ - Owner: `@unassigned`
189
+ - Effort: `M`
190
+ - Files: `webgui/state/statemanager.py`
191
+
192
+ - [ ] B3. Replace scattered manual active-ID patching in components with calls to the centralized helper.
193
+ - Owner: `@unassigned`
194
+ - Effort: `M`
195
+ - Files: `webgui/components/simulation.py`, `webgui/components/fitting.py`, others as needed
196
+
197
+ - [ ] B4. Add tests for cascade delete and active object reassignment across model/data/fit/sim.
198
+ - Owner: `@unassigned`
199
+ - Effort: `M`
200
+ - Files: `tests/`, `webgui/state/statemanager.py`
201
+
202
+ Acceptance criteria:
203
+ - After any delete/change action, all active IDs are either valid existing IDs or `None`.
204
+ - UI header and relevant panels refresh without exceptions after deletions.
205
+ - Cascade deletion behavior is deterministic and covered by tests.
206
+
207
+ ### C) Implement explicit expt data load/select/delete workflow
208
+
209
+ - [ ] C1. Add expt-data selector UI with active-item indicator and load action.
210
+ - Owner: `@unassigned`
211
+ - Effort: `M`
212
+ - Files: `webgui/components/data_import.py`
213
+
214
+ - [ ] C2. Add expt-data delete action with confirmation dialog and post-delete fallback selection logic.
215
+ - Owner: `@unassigned`
216
+ - Effort: `M`
217
+ - Files: `webgui/components/data_import.py`, `webgui/state/statemanager.py`
218
+
219
+ - [ ] C3. Emit and consume consistent `expt_data_changed` notifications so dependent panels refresh correctly.
220
+ - Owner: `@unassigned`
221
+ - Effort: `S`
222
+ - Files: `webgui/state/statemanager.py`, `webgui/components/body.py`, `webgui/components/header.py`, `webgui/components/data_model.py`, `webgui/components/fitting.py`
223
+
224
+ - [ ] C4. Add tests for selecting, loading, deleting multiple expt datasets and preserving app stability.
225
+ - Owner: `@unassigned`
226
+ - Effort: `M`
227
+ - Files: `tests/`
228
+
229
+ Acceptance criteria:
230
+ - User can select among multiple expt datasets, and active dataset is clearly shown.
231
+ - Deleting active expt dataset selects a valid fallback (or `None`) without stale references.
232
+ - Data Model and Fit panels always reflect the currently active expt dataset.
@@ -0,0 +1,89 @@
1
+ TODO
2
+
3
+ - Enable choosing of graph elements:
4
+ - What should be y-axis? Plot all species ideally
5
+ ----- see also https://community.plotly.com/t/possible-to-have-nested-or-hierarchical-legends/2376/8 for potential way to toggle species vs group
6
+ - Fix GUI grossness
7
+
8
+ model.py:
9
+ overwrite model should delete all fits and simulations associated with it, and then clean up all orphaned expt_data.
10
+
11
+
12
+ - if chemical shift column has spaces in it then parameters are given invalid names. need to sanitize or just call them delta1, delta2, etc.
13
+
14
+
15
+
16
+
17
+ allow comments alongside equilibria
18
+ graphs - y/x log options
19
+
20
+ cannot have tooltip on a disabled element; would need to wrap it in a ui.element() and set tooltip on that. body.py:164
21
+
22
+
23
+ - if there are many dep variables but we do not fit them all, the fit graph does not work because m1.obslist (len(dep vars)) != fit.calc_obs (which ignores unfitted dep vars e.g. chemical shifts)
24
+
25
+ - multiple expdatas -- need to implement load_data, delete_data
26
+ - check effect of changing a model on exptdata - it should be fine. but maybe we need to work in dict/uuids rather than indices. we should 'invalidate' expt_data when model changed but not necessarily delete it.
27
+ - fast exchange :'(
28
+
29
+ - statemanager, sim/fit deletions
30
+ --- make sure that they always adjust the active_sim properly
31
+ --- in the fit box, bind the inputs like in simulations (easy)
32
+
33
+ - quick data plotting for raw data
34
+ - saving calc data?
35
+ - saving graphs?
36
+ - save plots/data to png/pdf and csv
37
+
38
+ - mcmc
39
+ - allow expt_data selection on data page
40
+ - auto-title for fits
41
+ - check whether hasattr(..., "active_...") works as expected/is a good idea. probably not, because attr exists since it is a getter... we really want to be checking whether the value is None (or whatever the default is).
42
+ - add refresh-bindings as in model tab to other tabs.
43
+
44
+ - precompile numba (part done; do better)
45
+ - plot fit vs expt observables (not just speciation)
46
+
47
+ - chemical shifts/fast exchange
48
+ - fit graph seems to show lines from sim graph?
49
+
50
+
51
+
52
+
53
+ DONE:
54
+ component concs for simulation - also allow edits maybe to a preformed table (or upload csv!)
55
+ - automatically plot sim/fit results against a concentration that changes, not against H
56
+ - overall it might be better to not have a default model.... -- actually how about a selection of fixed default models, e.g. 1:1, 2:1, 1:2.
57
+ - add packaging code, make it easily distributable
58
+ - annoying problem that components on LHS of equation is different to order of components in a species on RHS
59
+ - indicator to header
60
+ - make data dep/indep into radio buttons
61
+ - overwrite model should prompt to save as.
62
+ - show fit results (and parameters), somehow
63
+ - remove "s" from delete dropdowns
64
+ - Read binding constants from controls
65
+ - Add a spinning wheel to indicate processing
66
+ - Replace graph e.g. with a plotly graph
67
+ - Ability to overlay multiple different models?
68
+ - Model name should give a clue as to its use in the plot (e.g. encourage user to give a descriptive name).
69
+ - Model name should be used as legend title.
70
+ - Enable selection of graph elements:
71
+ - What should be x-axis? Any component, species, or ratio thereof.
72
+ - What should be y-axis? Plot all species ideally
73
+ ----- maybe give an option to disable plotting of [comp]_free.
74
+ ----- use grouped legend <--- sadly, for now, this seems to make it impossible to toggle off single traces. :(
75
+ - Do we remember line visibility? NO. we should.
76
+ - default x-axis should be first varying component, notjust first component
77
+ - When a simulation is run with one conc range, then more steps in the same conc range are added, the graph currently seems to show the original data (first simulation) on an incorrect x-axis.
78
+ - Download and upload project
79
+ - if model name is blah, then ask if we should overwrite results
80
+ - Model persistence: on simulation, save model params results to session state.
81
+ - Load and edit models (dropdown? + button).
82
+ - so we should begin by instantiating a model with empty parameters and bind to/edit that.
83
+ - needs some architecture changes:
84
+ - model class
85
+ - sd.currmodel (property? or int index?)
86
+ - sd.models (list of models)
87
+ - Delete models.
88
+ - fix a bug where it seems like we cannot change the x-axis if "do not plot [comp]_free" is selected.
89
+ - plot loaded fit data (need to deal with compconcs sensibly -- re-calc via an expt_data_to_comp_concs function?)
@@ -1,54 +1,50 @@
1
1
  from nicegui import ui
2
2
 
3
- from .components import (
4
- BindToolsHeader,
5
- Body
6
- )
3
+ from .components import BindMCHeader, Body
7
4
  from .state.statemanager import StateManager
8
5
 
9
- class BindToolsServer:
10
6
 
7
+ class BindMCServer:
11
8
  def __init__(self):
12
9
 
13
10
  self.state_manager: StateManager = StateManager(load_prior_state=False) # Initialize state_manager attribute
14
- self.sm: StateManager =self.state_manager
11
+ self.sm: StateManager = self.state_manager
15
12
  self.components = {}
16
- self.body_components={}
13
+ self.body_components = {}
17
14
  self.tabs = {}
18
15
  self.setup_routes()
19
16
 
20
-
21
17
  def setup_routes(self):
22
18
  """Set up the application routes and UI components."""
23
19
 
24
20
  @ui.page("/")
25
-
26
- def index():
21
+ def index():
27
22
  self.state_manager = StateManager()
28
23
  self.sm = self.state_manager # alias
29
24
  self._generate_header()
30
25
  self._generate_body()
31
26
  self.body_components = self.components["body"].components
32
27
  self._load_prior_state()
33
-
34
-
35
28
 
36
29
  def _load_prior_state(self):
37
30
  # if simulations have been run already, populate the graph
38
31
  if len(self.sm.simulations) > 0:
39
32
  self.body_components["simulation"].graph.load_simulations_data()
40
- if self.sm.active_expt_data_id is not None and self.sm.active_expt_data.data is not None and not self.sm.active_expt_data.data.empty:
33
+ if (
34
+ self.sm.active_expt_data_id is not None
35
+ and self.sm.active_expt_data.data is not None
36
+ and not self.sm.active_expt_data.data.empty
37
+ ):
41
38
  self.sm.notify_listeners("data_imported")
42
39
  if len(self.sm.fits) > 0:
43
40
  self.sm.notify_listeners("fits_loaded")
44
41
  # self.components["fit_results"].sync_graphs()
45
42
  # self.components["fit_results"].generate_delete_fit_dropdown()
46
43
 
47
-
48
44
  def _generate_header(self):
49
- ui.colors(primary='#000000', secondary='grey-5', accent='blue-grey-5')
45
+ ui.colors(primary="#000000", secondary="grey-5", accent="blue-grey-5")
50
46
 
51
- self.components["header"] = BindToolsHeader(state_manager=self.state_manager)
47
+ self.components["header"] = BindMCHeader(state_manager=self.state_manager)
52
48
 
53
49
  def _generate_body(self):
54
- self.components["body"]= Body(self.state_manager)
50
+ self.components["body"] = Body(self.state_manager)
@@ -1,11 +1,6 @@
1
- import uuid
2
- from dataclasses import asdict, dataclass, field, InitVar
3
- from typing import Optional,Any
4
- import unicodedata
5
- from nicegui import binding
6
- import numpy as np
7
- import pandas as pd
8
- from lmfit import Parameter as LMFitParameter
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
9
4
 
10
5
  @dataclass
11
6
  class BindingConstant:
@@ -19,5 +14,3 @@ class BindingConstant:
19
14
  @property
20
15
  def name(self) -> str:
21
16
  return self.species
22
-
23
-