marimo-mmp 0.0.1__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 (32) hide show
  1. marimo_mmp-0.0.1/.gitignore +17 -0
  2. marimo_mmp-0.0.1/LICENSE +21 -0
  3. marimo_mmp-0.0.1/PKG-INFO +228 -0
  4. marimo_mmp-0.0.1/README.md +195 -0
  5. marimo_mmp-0.0.1/frontend/transform_graph/controls.ts +289 -0
  6. marimo_mmp-0.0.1/frontend/transform_graph/depiction.ts +5 -0
  7. marimo_mmp-0.0.1/frontend/transform_graph/dom.ts +38 -0
  8. marimo_mmp-0.0.1/frontend/transform_graph/encoding.ts +17 -0
  9. marimo_mmp-0.0.1/frontend/transform_graph/graph.ts +330 -0
  10. marimo_mmp-0.0.1/frontend/transform_graph/layout.ts +38 -0
  11. marimo_mmp-0.0.1/frontend/transform_graph/selection.ts +75 -0
  12. marimo_mmp-0.0.1/frontend/transform_graph/shell.ts +67 -0
  13. marimo_mmp-0.0.1/frontend/transform_graph/tooltips.ts +210 -0
  14. marimo_mmp-0.0.1/frontend/transform_graph/types.ts +191 -0
  15. marimo_mmp-0.0.1/frontend/transform_graph/viewport.ts +140 -0
  16. marimo_mmp-0.0.1/frontend/transform_graph.css +163 -0
  17. marimo_mmp-0.0.1/frontend/transform_graph.ts +123 -0
  18. marimo_mmp-0.0.1/package-lock.json +627 -0
  19. marimo_mmp-0.0.1/package.json +20 -0
  20. marimo_mmp-0.0.1/pyproject.toml +105 -0
  21. marimo_mmp-0.0.1/scripts/hatch_build.py +43 -0
  22. marimo_mmp-0.0.1/src/marimo_mmp/__init__.py +33 -0
  23. marimo_mmp-0.0.1/src/marimo_mmp/dataset.py +425 -0
  24. marimo_mmp-0.0.1/src/marimo_mmp/depiction.py +88 -0
  25. marimo_mmp-0.0.1/src/marimo_mmp/models.py +241 -0
  26. marimo_mmp-0.0.1/src/marimo_mmp/parsing.py +329 -0
  27. marimo_mmp-0.0.1/src/marimo_mmp/provenance.py +131 -0
  28. marimo_mmp-0.0.1/src/marimo_mmp/py.typed +0 -0
  29. marimo_mmp-0.0.1/src/marimo_mmp/static/transform_graph.css +1 -0
  30. marimo_mmp-0.0.1/src/marimo_mmp/static/transform_graph.js +4 -0
  31. marimo_mmp-0.0.1/src/marimo_mmp/widget.py +627 -0
  32. marimo_mmp-0.0.1/tsconfig.json +14 -0
@@ -0,0 +1,17 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Rebuildable mmpdb intermediate
13
+ data/processed/*.fragdb
14
+ __marimo__
15
+ node_modules/
16
+ src/marimo_mmp/static/transform_graph.js
17
+ src/marimo_mmp/static/transform_graph.css
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anton Siomchen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,228 @@
1
+ Metadata-Version: 2.5
2
+ Name: marimo-mmp
3
+ Version: 0.0.1
4
+ Summary: Reactive visualization of mmpdb transform results
5
+ Project-URL: Homepage, https://github.com/asiomchen/marimo_mmp
6
+ Project-URL: Repository, https://github.com/asiomchen/marimo_mmp
7
+ Project-URL: Issues, https://github.com/asiomchen/marimo_mmp/issues
8
+ Project-URL: Documentation, https://github.com/asiomchen/marimo_mmp/blob/main/README.md
9
+ Author-email: Anton Siomchen <41703271+asiomchen@users.noreply.github.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: anywidget,cheminformatics,marimo,matched molecular pairs,medicinal chemistry,mmpdb,rdkit,visualization
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
23
+ Classifier: Topic :: Scientific/Engineering :: Visualization
24
+ Classifier: Typing :: Typed
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: anywidget>=0.9
27
+ Requires-Dist: pandas>=2.2.2
28
+ Requires-Dist: rdkit>=2024.9.1
29
+ Requires-Dist: traitlets>=5
30
+ Provides-Extra: notebook
31
+ Requires-Dist: marimo>=0.24.0; extra == 'notebook'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # marimo_mmp
35
+
36
+ [![Python ≥3.11](https://img.shields.io/badge/Python-%E2%89%A53.11-3776AB?logo=python&logoColor=white)](https://github.com/asiomchen/marimo_mmp/blob/main/pyproject.toml)
37
+ [![TypeScript strict](https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript&logoColor=white)](https://github.com/asiomchen/marimo_mmp/blob/main/tsconfig.json)
38
+ [![anywidget](https://img.shields.io/badge/widget-anywidget-7259D6)](https://anywidget.dev/)
39
+
40
+ `marimo-mmp` visualizes `mmpdb transform` results as an interactive molecular
41
+ graph: query compound, transformation rules, and generated products. Filter by
42
+ effect and support, select products, and inspect source pairs. It uses anywidget;
43
+ marimo is optional. Packaged JavaScript and CSS need no CDN or runtime npm.
44
+
45
+ Use `mmpdb>=3.1.3` to [prepare input data](#preparing-data-with-mmpdb).
46
+
47
+
48
+ ## Quickstart
49
+
50
+ Requires Python ≥3.11. Install with pip:
51
+
52
+ ```
53
+ pip install 'marimo-mmp[notebook]'
54
+ ```
55
+ Or with uv:
56
+ ```bash
57
+ uv add 'marimo-mmp[notebook]'
58
+ ```
59
+
60
+
61
+ ```python
62
+ import marimo as mo
63
+
64
+ from marimo_mmp import (
65
+ EvidenceThresholds,
66
+ TransformDataset,
67
+ TransformFilters,
68
+ TransformGraph,
69
+ )
70
+
71
+ dataset = TransformDataset.from_tsv(
72
+ "transforms.tsv",
73
+ original_smiles="CCO", # optional query SMILES
74
+ mmpdb_path="assay.mmpdb", # optional provenance database
75
+ evidence_thresholds=EvidenceThresholds(moderate=2, strong=5),
76
+ )
77
+ graph = mo.ui.anywidget(
78
+ TransformGraph(
79
+ dataset,
80
+ property_name="pIC50",
81
+ filters=TransformFilters(effect="gain", min_support=2),
82
+ max_nodes=100,
83
+ )
84
+ )
85
+ graph
86
+ ```
87
+
88
+ In marimo, assign `graph` in one cell and read its immutable
89
+ `TransformGraphState` in a downstream cell that reruns on interaction:
90
+
91
+ ```python
92
+ state = graph.state
93
+ state.selected_compound, state.selected_stats # typed records, or None
94
+ state.property_name, state.filters # active property and typed filters
95
+ state.shown_count, state.matching_count # rendered versus matching products
96
+ state.rows() # table-ready rows
97
+ state.source_pairs() # in-memory pairs for selected product
98
+ ```
99
+
100
+ `graph.value` is marimo's synchronized trait dictionary; `graph.widget` is the
101
+ raw widget. `graph.update(dataset, property_name=..., filters=..., max_nodes=...)`
102
+ retains a still-visible selection. Omitted options select the dataset's first
103
+ property, all products, and a limit of 100; direction retains its current value
104
+ unless supplied. Other anywidget hosts display `TransformGraph(dataset)` directly. The
105
+ [explorer notebook](https://github.com/asiomchen/marimo_mmp/blob/main/notebooks/transform_explorer.py) includes the full state reference.
106
+
107
+ Changed-atom highlighting is off by default. Enable it with
108
+ `TransformGraph(dataset, highlight_changes=True)` when the dataset has query SMILES.
109
+ Highlighting can make the first render slower because it searches for the common
110
+ substructure of each product and the query; subsequent renders reuse cached SVGs.
111
+
112
+ ## Preparing data with mmpdb
113
+
114
+ Use [mmpdb](https://github.com/rdkit/mmpdb) to build a matched-pair database and
115
+ apply its transformations to a query compound. With `compounds.smi` containing
116
+ SMILES and compound IDs, and `properties.tsv` containing an `ID` column and a
117
+ numeric `pIC50` column with matching IDs:
118
+
119
+ ```bash
120
+ pip install 'mmpdb>=3.1.3'
121
+ mmpdb fragment compounds.smi --num-jobs 1 -o compounds.fragdb
122
+ mmpdb index compounds.fragdb --properties properties.tsv -o assay.mmpdb
123
+ mmpdb transform assay.mmpdb --smiles 'CCO' --property pIC50 -o transforms.tsv
124
+ ```
125
+
126
+ Replace `CCO` and `pIC50` with your query SMILES and property name. Use the same
127
+ query SMILES as `original_smiles` when loading the output in the quickstart.
128
+
129
+ | Output | Use in the widget |
130
+ |---|---|
131
+ | `transforms.tsv` from `mmpdb transform` | Required input: generated product SMILES, transformation rules, environments, and property-change statistics. |
132
+ | `assay.mmpdb` from `mmpdb index` | Optional SQLite input via `mmpdb_path=...`: source compound pairs and their measured property values for provenance. Use the same database that generated the TSV. |
133
+ | `compounds.fragdb` from `mmpdb fragment` | Intermediate used by indexing; the widget does not read it. |
134
+
135
+ Keep property statistics in the transform output; `--no-properties`,
136
+ `mmpdb generate` output, and pair tables exported by `mmpdb index` do not supply the columns the widget requires. The widget loads existing TSV and SQLite files directly, so the `mmpdb` Python package is needed only for data generation. The
137
+ repository's development dependency group includes its CLI.
138
+
139
+ ## Data and API
140
+
141
+ `TransformDataset.from_tsv` accepts paths, bytes, or readable streams of UTF-8
142
+ TSV/CSV; `from_df` accepts pandas DataFrames. Both validate
143
+ `ID`, `SMILES`, and mmpdb statistic columns and discover property families.
144
+ Invalid transform data raises `TransformValidationError`. Optional MMPDBs are
145
+ validated and opened read-only during loading. Duplicate column names, empty
146
+ rule fragments, negative standard deviations, p-values outside `[0, 1]`, and
147
+ out-of-order min/quartile/median/max summaries are rejected. Source pairs for
148
+ every transform and property, including pairs with missing values, are stored in memory;
149
+ `source_pairs()` needs no further database access. The database file can be
150
+ removed after loading. `dataset.mmpdb_path` retains its original path as source
151
+ metadata. Larger provenance sets increase loading time and memory use.
152
+
153
+ | Parameter | Meaning |
154
+ |---|---|
155
+ | `TransformGraph(dataset, property_name=..., max_nodes=100)` | Property from `dataset.properties` (default: first); product limit after filtering and ranking. |
156
+ | `TransformGraph(..., direction="higher")` | Favorable orientation: `higher` or `lower`; controls gain/loss filtering and colors. |
157
+ | `TransformFilters(effect=...)` | `all` (default), `gain`, `loss`, or `neutral`, following the orientation. |
158
+ | Other filter fields | `min_abs_effect`, `min_support`, `radii`, `quality`, `text`, `max_std`, `max_p_value`. Use tuples for radii and evidence names in `quality`. |
159
+ | `EvidenceThresholds(moderate=2, strong=5)` | Inclusive pair-count minima: Moderate ≥2; Strong > Moderate. |
160
+ | `TransformGraph(..., height=1220)` | Stage height cap in pixels (minimum 480), also limited by the viewport. |
161
+ | `TransformGraph(..., highlight_changes=False)` | Constructor setting for changed-atom highlights; retained across updates and copies. Query structure remains visible when highlighting is off. |
162
+
163
+ Default evidence tiers summarize database support: **Exploratory** = 1 pair,
164
+ **Moderate** = 2–4, **Strong** ≥5. Generated products are not experimentally
165
+ validated by these labels. Missing standard deviation, quartiles, or p-values
166
+ produce warnings. Effects are supplied property deltas. Changing evidence chips
167
+ resets minimum support to 1; changing minimum support selects all evidence levels.
168
+
169
+ For data-only filtering and table export, `dataset.view(...)` remains available
170
+ and provides `rows()` and `source_pairs()` without constructing a widget.
171
+
172
+ ## Example data
173
+
174
+ The explorer and tests use `data/processed/bilastine_transforms.tsv` and
175
+ `data/processed/h1_ic50.mmpdb`. These examples derive from ChEMBL 37 data for the
176
+ human histamine H1 receptor (HRH1, UniProt `P35367`,
177
+ [ChEMBL target `CHEMBL231`](https://www.ebi.ac.uk/chembl/explore/target/CHEMBL231)),
178
+ retrieved on August 26, 2026. Cite ChEMBL 37 when reusing this derived data.
179
+ [build_report.json](https://github.com/asiomchen/marimo_mmp/blob/main/data/processed/build_report.json) records the release,
180
+ retrieval timestamp, and validation counts.
181
+
182
+ The database uses exact, positive IC50 measurements in nM from direct human H1
183
+ binding assays, excluding potential duplicates and records with data-validity
184
+ comments. RDKit cleanup and parent-fragment selection standardized structures.
185
+ Each measurement was converted to `pIC50 = 9 - log10(IC50_nM)`; the median per
186
+ parent ChEMBL molecule became its sole property. The selection retained 117
187
+ measurements across 107 compounds, with 74 compounds indexed in the MMPDB.
188
+
189
+ ## Contributing
190
+
191
+ Use uv with Python 3.11 and Node.js ≥20. From the repository root:
192
+
193
+ ```bash
194
+ npm ci
195
+ uv sync --locked --python 3.11 --group dev
196
+ npm run build
197
+ uv run marimo edit notebooks/transform_explorer.py
198
+ ```
199
+
200
+ Sources: Python in `src/marimo_mmp/`, TypeScript/CSS in `frontend/`, examples in
201
+ `notebooks/`, tools in `scripts/`. See [WIDGET_ARCHITECTURE.md](https://github.com/asiomchen/marimo_mmp/blob/main/WIDGET_ARCHITECTURE.md)
202
+ for internals and [AGENTS.md](https://github.com/asiomchen/marimo_mmp/blob/main/AGENTS.md) for conventions.
203
+
204
+ Run the CI checks and package verification:
205
+
206
+ ```bash
207
+ npm run check
208
+ uv run ruff check src tests scripts
209
+ uv run ruff format --check src tests scripts
210
+ uv run ty check
211
+ uv run pytest
212
+ uv run marimo check --strict notebooks/*.py
213
+ uv run hatch build --clean
214
+ uv run python scripts/verify_distribution_assets.py dist/*
215
+ ```
216
+
217
+ `npm run check` type-checks TypeScript and tests rebuilt assets. After frontend
218
+ edits, run `npm run build`, or `npm run dev` to watch. Runtime assets in
219
+ `src/marimo_mmp/static/` are gitignored; Hatch builds missing assets and includes
220
+ them in wheels/sdists. Use `uv run hatch version [VERSION]` to inspect/update the
221
+ version. Ruff also runs via pre-commit.
222
+
223
+ ## License
224
+
225
+ Code and documentation are licensed under the [MIT License](https://github.com/asiomchen/marimo_mmp/blob/main/LICENSE).
226
+ The ChEMBL-derived example data is distributed under
227
+ [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/); see
228
+ [Example data](#example-data) for provenance and attribution.
@@ -0,0 +1,195 @@
1
+ # marimo_mmp
2
+
3
+ [![Python ≥3.11](https://img.shields.io/badge/Python-%E2%89%A53.11-3776AB?logo=python&logoColor=white)](https://github.com/asiomchen/marimo_mmp/blob/main/pyproject.toml)
4
+ [![TypeScript strict](https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript&logoColor=white)](https://github.com/asiomchen/marimo_mmp/blob/main/tsconfig.json)
5
+ [![anywidget](https://img.shields.io/badge/widget-anywidget-7259D6)](https://anywidget.dev/)
6
+
7
+ `marimo-mmp` visualizes `mmpdb transform` results as an interactive molecular
8
+ graph: query compound, transformation rules, and generated products. Filter by
9
+ effect and support, select products, and inspect source pairs. It uses anywidget;
10
+ marimo is optional. Packaged JavaScript and CSS need no CDN or runtime npm.
11
+
12
+ Use `mmpdb>=3.1.3` to [prepare input data](#preparing-data-with-mmpdb).
13
+
14
+
15
+ ## Quickstart
16
+
17
+ Requires Python ≥3.11. Install with pip:
18
+
19
+ ```
20
+ pip install 'marimo-mmp[notebook]'
21
+ ```
22
+ Or with uv:
23
+ ```bash
24
+ uv add 'marimo-mmp[notebook]'
25
+ ```
26
+
27
+
28
+ ```python
29
+ import marimo as mo
30
+
31
+ from marimo_mmp import (
32
+ EvidenceThresholds,
33
+ TransformDataset,
34
+ TransformFilters,
35
+ TransformGraph,
36
+ )
37
+
38
+ dataset = TransformDataset.from_tsv(
39
+ "transforms.tsv",
40
+ original_smiles="CCO", # optional query SMILES
41
+ mmpdb_path="assay.mmpdb", # optional provenance database
42
+ evidence_thresholds=EvidenceThresholds(moderate=2, strong=5),
43
+ )
44
+ graph = mo.ui.anywidget(
45
+ TransformGraph(
46
+ dataset,
47
+ property_name="pIC50",
48
+ filters=TransformFilters(effect="gain", min_support=2),
49
+ max_nodes=100,
50
+ )
51
+ )
52
+ graph
53
+ ```
54
+
55
+ In marimo, assign `graph` in one cell and read its immutable
56
+ `TransformGraphState` in a downstream cell that reruns on interaction:
57
+
58
+ ```python
59
+ state = graph.state
60
+ state.selected_compound, state.selected_stats # typed records, or None
61
+ state.property_name, state.filters # active property and typed filters
62
+ state.shown_count, state.matching_count # rendered versus matching products
63
+ state.rows() # table-ready rows
64
+ state.source_pairs() # in-memory pairs for selected product
65
+ ```
66
+
67
+ `graph.value` is marimo's synchronized trait dictionary; `graph.widget` is the
68
+ raw widget. `graph.update(dataset, property_name=..., filters=..., max_nodes=...)`
69
+ retains a still-visible selection. Omitted options select the dataset's first
70
+ property, all products, and a limit of 100; direction retains its current value
71
+ unless supplied. Other anywidget hosts display `TransformGraph(dataset)` directly. The
72
+ [explorer notebook](https://github.com/asiomchen/marimo_mmp/blob/main/notebooks/transform_explorer.py) includes the full state reference.
73
+
74
+ Changed-atom highlighting is off by default. Enable it with
75
+ `TransformGraph(dataset, highlight_changes=True)` when the dataset has query SMILES.
76
+ Highlighting can make the first render slower because it searches for the common
77
+ substructure of each product and the query; subsequent renders reuse cached SVGs.
78
+
79
+ ## Preparing data with mmpdb
80
+
81
+ Use [mmpdb](https://github.com/rdkit/mmpdb) to build a matched-pair database and
82
+ apply its transformations to a query compound. With `compounds.smi` containing
83
+ SMILES and compound IDs, and `properties.tsv` containing an `ID` column and a
84
+ numeric `pIC50` column with matching IDs:
85
+
86
+ ```bash
87
+ pip install 'mmpdb>=3.1.3'
88
+ mmpdb fragment compounds.smi --num-jobs 1 -o compounds.fragdb
89
+ mmpdb index compounds.fragdb --properties properties.tsv -o assay.mmpdb
90
+ mmpdb transform assay.mmpdb --smiles 'CCO' --property pIC50 -o transforms.tsv
91
+ ```
92
+
93
+ Replace `CCO` and `pIC50` with your query SMILES and property name. Use the same
94
+ query SMILES as `original_smiles` when loading the output in the quickstart.
95
+
96
+ | Output | Use in the widget |
97
+ |---|---|
98
+ | `transforms.tsv` from `mmpdb transform` | Required input: generated product SMILES, transformation rules, environments, and property-change statistics. |
99
+ | `assay.mmpdb` from `mmpdb index` | Optional SQLite input via `mmpdb_path=...`: source compound pairs and their measured property values for provenance. Use the same database that generated the TSV. |
100
+ | `compounds.fragdb` from `mmpdb fragment` | Intermediate used by indexing; the widget does not read it. |
101
+
102
+ Keep property statistics in the transform output; `--no-properties`,
103
+ `mmpdb generate` output, and pair tables exported by `mmpdb index` do not supply the columns the widget requires. The widget loads existing TSV and SQLite files directly, so the `mmpdb` Python package is needed only for data generation. The
104
+ repository's development dependency group includes its CLI.
105
+
106
+ ## Data and API
107
+
108
+ `TransformDataset.from_tsv` accepts paths, bytes, or readable streams of UTF-8
109
+ TSV/CSV; `from_df` accepts pandas DataFrames. Both validate
110
+ `ID`, `SMILES`, and mmpdb statistic columns and discover property families.
111
+ Invalid transform data raises `TransformValidationError`. Optional MMPDBs are
112
+ validated and opened read-only during loading. Duplicate column names, empty
113
+ rule fragments, negative standard deviations, p-values outside `[0, 1]`, and
114
+ out-of-order min/quartile/median/max summaries are rejected. Source pairs for
115
+ every transform and property, including pairs with missing values, are stored in memory;
116
+ `source_pairs()` needs no further database access. The database file can be
117
+ removed after loading. `dataset.mmpdb_path` retains its original path as source
118
+ metadata. Larger provenance sets increase loading time and memory use.
119
+
120
+ | Parameter | Meaning |
121
+ |---|---|
122
+ | `TransformGraph(dataset, property_name=..., max_nodes=100)` | Property from `dataset.properties` (default: first); product limit after filtering and ranking. |
123
+ | `TransformGraph(..., direction="higher")` | Favorable orientation: `higher` or `lower`; controls gain/loss filtering and colors. |
124
+ | `TransformFilters(effect=...)` | `all` (default), `gain`, `loss`, or `neutral`, following the orientation. |
125
+ | Other filter fields | `min_abs_effect`, `min_support`, `radii`, `quality`, `text`, `max_std`, `max_p_value`. Use tuples for radii and evidence names in `quality`. |
126
+ | `EvidenceThresholds(moderate=2, strong=5)` | Inclusive pair-count minima: Moderate ≥2; Strong > Moderate. |
127
+ | `TransformGraph(..., height=1220)` | Stage height cap in pixels (minimum 480), also limited by the viewport. |
128
+ | `TransformGraph(..., highlight_changes=False)` | Constructor setting for changed-atom highlights; retained across updates and copies. Query structure remains visible when highlighting is off. |
129
+
130
+ Default evidence tiers summarize database support: **Exploratory** = 1 pair,
131
+ **Moderate** = 2–4, **Strong** ≥5. Generated products are not experimentally
132
+ validated by these labels. Missing standard deviation, quartiles, or p-values
133
+ produce warnings. Effects are supplied property deltas. Changing evidence chips
134
+ resets minimum support to 1; changing minimum support selects all evidence levels.
135
+
136
+ For data-only filtering and table export, `dataset.view(...)` remains available
137
+ and provides `rows()` and `source_pairs()` without constructing a widget.
138
+
139
+ ## Example data
140
+
141
+ The explorer and tests use `data/processed/bilastine_transforms.tsv` and
142
+ `data/processed/h1_ic50.mmpdb`. These examples derive from ChEMBL 37 data for the
143
+ human histamine H1 receptor (HRH1, UniProt `P35367`,
144
+ [ChEMBL target `CHEMBL231`](https://www.ebi.ac.uk/chembl/explore/target/CHEMBL231)),
145
+ retrieved on August 26, 2026. Cite ChEMBL 37 when reusing this derived data.
146
+ [build_report.json](https://github.com/asiomchen/marimo_mmp/blob/main/data/processed/build_report.json) records the release,
147
+ retrieval timestamp, and validation counts.
148
+
149
+ The database uses exact, positive IC50 measurements in nM from direct human H1
150
+ binding assays, excluding potential duplicates and records with data-validity
151
+ comments. RDKit cleanup and parent-fragment selection standardized structures.
152
+ Each measurement was converted to `pIC50 = 9 - log10(IC50_nM)`; the median per
153
+ parent ChEMBL molecule became its sole property. The selection retained 117
154
+ measurements across 107 compounds, with 74 compounds indexed in the MMPDB.
155
+
156
+ ## Contributing
157
+
158
+ Use uv with Python 3.11 and Node.js ≥20. From the repository root:
159
+
160
+ ```bash
161
+ npm ci
162
+ uv sync --locked --python 3.11 --group dev
163
+ npm run build
164
+ uv run marimo edit notebooks/transform_explorer.py
165
+ ```
166
+
167
+ Sources: Python in `src/marimo_mmp/`, TypeScript/CSS in `frontend/`, examples in
168
+ `notebooks/`, tools in `scripts/`. See [WIDGET_ARCHITECTURE.md](https://github.com/asiomchen/marimo_mmp/blob/main/WIDGET_ARCHITECTURE.md)
169
+ for internals and [AGENTS.md](https://github.com/asiomchen/marimo_mmp/blob/main/AGENTS.md) for conventions.
170
+
171
+ Run the CI checks and package verification:
172
+
173
+ ```bash
174
+ npm run check
175
+ uv run ruff check src tests scripts
176
+ uv run ruff format --check src tests scripts
177
+ uv run ty check
178
+ uv run pytest
179
+ uv run marimo check --strict notebooks/*.py
180
+ uv run hatch build --clean
181
+ uv run python scripts/verify_distribution_assets.py dist/*
182
+ ```
183
+
184
+ `npm run check` type-checks TypeScript and tests rebuilt assets. After frontend
185
+ edits, run `npm run build`, or `npm run dev` to watch. Runtime assets in
186
+ `src/marimo_mmp/static/` are gitignored; Hatch builds missing assets and includes
187
+ them in wheels/sdists. Use `uv run hatch version [VERSION]` to inspect/update the
188
+ version. Ruff also runs via pre-commit.
189
+
190
+ ## License
191
+
192
+ Code and documentation are licensed under the [MIT License](https://github.com/asiomchen/marimo_mmp/blob/main/LICENSE).
193
+ The ChEMBL-derived example data is distributed under
194
+ [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/); see
195
+ [Example data](#example-data) for provenance and attribution.