polynet 1.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.
- polynet-1.0.1/LICENSE +21 -0
- polynet-1.0.1/PKG-INFO +320 -0
- polynet-1.0.1/README.md +279 -0
- polynet-1.0.1/polynet/__init__.py +8 -0
- polynet-1.0.1/polynet/app/Welcome_to_PolyNet.py +82 -0
- polynet-1.0.1/polynet/app/components/experiments.py +22 -0
- polynet-1.0.1/polynet/app/components/figure_export.py +87 -0
- polynet-1.0.1/polynet/app/components/forms/analyse_results.py +825 -0
- polynet-1.0.1/polynet/app/components/forms/applicability_domain.py +108 -0
- polynet-1.0.1/polynet/app/components/forms/create_experiment.py +501 -0
- polynet-1.0.1/polynet/app/components/forms/explain_model.py +684 -0
- polynet-1.0.1/polynet/app/components/forms/explain_tml.py +481 -0
- polynet-1.0.1/polynet/app/components/forms/explanation_plots.py +441 -0
- polynet-1.0.1/polynet/app/components/forms/fragment_plots.py +187 -0
- polynet-1.0.1/polynet/app/components/forms/plot_customiser.py +102 -0
- polynet-1.0.1/polynet/app/components/forms/representation.py +816 -0
- polynet-1.0.1/polynet/app/components/forms/search_grid.py +158 -0
- polynet-1.0.1/polynet/app/components/forms/train_models.py +1180 -0
- polynet-1.0.1/polynet/app/components/graph_display.py +197 -0
- polynet-1.0.1/polynet/app/components/optional_dependencies.py +50 -0
- polynet-1.0.1/polynet/app/components/plots.py +238 -0
- polynet-1.0.1/polynet/app/options/allowable_sets.py +3 -0
- polynet-1.0.1/polynet/app/options/file_paths.py +80 -0
- polynet-1.0.1/polynet/app/options/plot.py +21 -0
- polynet-1.0.1/polynet/app/options/state_keys.py +331 -0
- polynet-1.0.1/polynet/app/pages/1_Create_Experiment.py +108 -0
- polynet-1.0.1/polynet/app/pages/2_Representation.py +202 -0
- polynet-1.0.1/polynet/app/pages/3_Train_Models.py +560 -0
- polynet-1.0.1/polynet/app/pages/4_Predict.py +264 -0
- polynet-1.0.1/polynet/app/pages/5_Explain_Models.py +295 -0
- polynet-1.0.1/polynet/app/pages/6_Analyse_Results.py +203 -0
- polynet-1.0.1/polynet/app/services/cache.py +47 -0
- polynet-1.0.1/polynet/app/services/configurations.py +9 -0
- polynet-1.0.1/polynet/app/services/experiments.py +3 -0
- polynet-1.0.1/polynet/app/services/explain_model.py +282 -0
- polynet-1.0.1/polynet/app/services/explain_source.py +143 -0
- polynet-1.0.1/polynet/app/services/explain_tml.py +212 -0
- polynet-1.0.1/polynet/app/services/explanation_results.py +345 -0
- polynet-1.0.1/polynet/app/services/graph_viz.py +494 -0
- polynet-1.0.1/polynet/app/services/model_training.py +19 -0
- polynet-1.0.1/polynet/app/services/predict_model.py +3 -0
- polynet-1.0.1/polynet/app/services/progress.py +85 -0
- polynet-1.0.1/polynet/app/services/reruns.py +274 -0
- polynet-1.0.1/polynet/app/services/workload.py +54 -0
- polynet-1.0.1/polynet/app/static/polynet.png +0 -0
- polynet-1.0.1/polynet/app/utils/__init__.py +13 -0
- polynet-1.0.1/polynet/applicability/__init__.py +27 -0
- polynet-1.0.1/polynet/applicability/assess.py +458 -0
- polynet-1.0.1/polynet/applicability/calibration.py +111 -0
- polynet-1.0.1/polynet/applicability/domain.py +166 -0
- polynet-1.0.1/polynet/applicability/reference.py +159 -0
- polynet-1.0.1/polynet/applicability/similarity.py +140 -0
- polynet-1.0.1/polynet/cli.py +146 -0
- polynet-1.0.1/polynet/config/_loader.py +447 -0
- polynet-1.0.1/polynet/config/column_names.py +154 -0
- polynet-1.0.1/polynet/config/constants.py +64 -0
- polynet-1.0.1/polynet/config/display_names.py +148 -0
- polynet-1.0.1/polynet/config/enums.py +501 -0
- polynet-1.0.1/polynet/config/experiment.py +306 -0
- polynet-1.0.1/polynet/config/from_app.py +279 -0
- polynet-1.0.1/polynet/config/from_yaml.py +145 -0
- polynet-1.0.1/polynet/config/io.py +57 -0
- polynet-1.0.1/polynet/config/paths.py +379 -0
- polynet-1.0.1/polynet/config/schemas/__init__.py +47 -0
- polynet-1.0.1/polynet/config/schemas/applicability_domain.py +88 -0
- polynet-1.0.1/polynet/config/schemas/base.py +170 -0
- polynet-1.0.1/polynet/config/schemas/data.py +129 -0
- polynet-1.0.1/polynet/config/schemas/explainability.py +128 -0
- polynet-1.0.1/polynet/config/schemas/feature_preprocessing.py +101 -0
- polynet-1.0.1/polynet/config/schemas/fingerprints.py +174 -0
- polynet-1.0.1/polynet/config/schemas/general.py +47 -0
- polynet-1.0.1/polynet/config/schemas/plotting.py +59 -0
- polynet-1.0.1/polynet/config/schemas/representation.py +165 -0
- polynet-1.0.1/polynet/config/schemas/split_data.py +229 -0
- polynet-1.0.1/polynet/config/schemas/target_preprocessing.py +43 -0
- polynet-1.0.1/polynet/config/schemas/tml_explainability.py +116 -0
- polynet-1.0.1/polynet/config/schemas/training.py +473 -0
- polynet-1.0.1/polynet/config/search_grid.py +420 -0
- polynet-1.0.1/polynet/data/__init__.py +24 -0
- polynet-1.0.1/polynet/data/benchmarks/fluorine_mri_snr.csv +419 -0
- polynet-1.0.1/polynet/data/creator.py +193 -0
- polynet-1.0.1/polynet/data/feature_transformer.py +344 -0
- polynet-1.0.1/polynet/data/loader.py +245 -0
- polynet-1.0.1/polynet/data/preprocessing.py +406 -0
- polynet-1.0.1/polynet/data/sampling.py +134 -0
- polynet-1.0.1/polynet/data/structures.py +206 -0
- polynet-1.0.1/polynet/experiment/__init__.py +13 -0
- polynet-1.0.1/polynet/experiment/manager.py +50 -0
- polynet-1.0.1/polynet/explainability/__init__.py +124 -0
- polynet-1.0.1/polynet/explainability/attributions.py +37 -0
- polynet-1.0.1/polynet/explainability/embeddings.py +121 -0
- polynet-1.0.1/polynet/explainability/explain.py +959 -0
- polynet-1.0.1/polynet/explainability/fragment_figures.py +224 -0
- polynet-1.0.1/polynet/explainability/masking.py +635 -0
- polynet-1.0.1/polynet/explainability/selection.py +177 -0
- polynet-1.0.1/polynet/explainability/shap_explain.py +1359 -0
- polynet-1.0.1/polynet/explainability/visualization.py +850 -0
- polynet-1.0.1/polynet/factories/__init__.py +51 -0
- polynet-1.0.1/polynet/factories/dataloader.py +571 -0
- polynet-1.0.1/polynet/factories/loss.py +102 -0
- polynet-1.0.1/polynet/factories/network.py +187 -0
- polynet-1.0.1/polynet/factories/optimizer.py +218 -0
- polynet-1.0.1/polynet/featurizer/__init__.py +45 -0
- polynet-1.0.1/polynet/featurizer/allowable_sets.py +82 -0
- polynet-1.0.1/polynet/featurizer/descriptors.py +838 -0
- polynet-1.0.1/polynet/featurizer/graph.py +208 -0
- polynet-1.0.1/polynet/featurizer/pmx.py +450 -0
- polynet-1.0.1/polynet/featurizer/polymer_graph.py +508 -0
- polynet-1.0.1/polynet/featurizer/selection.py +278 -0
- polynet-1.0.1/polynet/inference/__init__.py +25 -0
- polynet-1.0.1/polynet/inference/ensemble.py +108 -0
- polynet-1.0.1/polynet/inference/gnn.py +157 -0
- polynet-1.0.1/polynet/inference/predict.py +154 -0
- polynet-1.0.1/polynet/inference/tml.py +155 -0
- polynet-1.0.1/polynet/inference/utils.py +108 -0
- polynet-1.0.1/polynet/models/__init__.py +66 -0
- polynet-1.0.1/polynet/models/base.py +665 -0
- polynet-1.0.1/polynet/models/gnn/__init__.py +40 -0
- polynet-1.0.1/polynet/models/gnn/cgcnn.py +248 -0
- polynet-1.0.1/polynet/models/gnn/cggnn.py +12 -0
- polynet-1.0.1/polynet/models/gnn/gat.py +161 -0
- polynet-1.0.1/polynet/models/gnn/gcn.py +211 -0
- polynet-1.0.1/polynet/models/gnn/graphsage.py +210 -0
- polynet-1.0.1/polynet/models/gnn/mpnn.py +230 -0
- polynet-1.0.1/polynet/models/gnn/transformer.py +163 -0
- polynet-1.0.1/polynet/models/persistence.py +237 -0
- polynet-1.0.1/polynet/pipeline/__init__.py +53 -0
- polynet-1.0.1/polynet/pipeline/runner.py +777 -0
- polynet-1.0.1/polynet/pipeline/self_check.py +348 -0
- polynet-1.0.1/polynet/pipeline/stages.py +1550 -0
- polynet-1.0.1/polynet/plotting/data_analysis.py +75 -0
- polynet-1.0.1/polynet/training/__init__.py +34 -0
- polynet-1.0.1/polynet/training/cv.py +55 -0
- polynet-1.0.1/polynet/training/evaluate.py +199 -0
- polynet-1.0.1/polynet/training/gnn.py +698 -0
- polynet-1.0.1/polynet/training/hyperopt.py +617 -0
- polynet-1.0.1/polynet/training/metrics.py +276 -0
- polynet-1.0.1/polynet/training/tml.py +477 -0
- polynet-1.0.1/polynet/utils/__init__.py +104 -0
- polynet-1.0.1/polynet/utils/chem_utils.py +383 -0
- polynet-1.0.1/polynet/utils/data_preprocessing.py +127 -0
- polynet-1.0.1/polynet/utils/graph_analysis.py +222 -0
- polynet-1.0.1/polynet/utils/optional_dependencies.py +91 -0
- polynet-1.0.1/polynet/utils/statistical_analysis.py +303 -0
- polynet-1.0.1/polynet/utils/validation.py +211 -0
- polynet-1.0.1/polynet/visualization/__init__.py +35 -0
- polynet-1.0.1/polynet/visualization/plots.py +480 -0
- polynet-1.0.1/polynet/visualization/utils.py +34 -0
- polynet-1.0.1/pyproject.toml +90 -0
polynet-1.0.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025–2026 Eduardo Aguilar
|
|
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.
|
polynet-1.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: polynet
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: A Python package for polymer informatics: property prediction with graph neural networks and traditional machine learning
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: polymer informatics,graph neural networks,machine learning,explainability
|
|
8
|
+
Author: Eduardo Aguilar-Bejarano
|
|
9
|
+
Author-email: eduardo.aguilar-bejarano@nottingham.ac.uk
|
|
10
|
+
Requires-Python: >=3.11,<3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
14
|
+
Requires-Dist: astartes (>=1.3.3,<2.0.0)
|
|
15
|
+
Requires-Dist: imbalanced-learn (>=0.14.0,<0.15.0)
|
|
16
|
+
Requires-Dist: matplotlib (>=3.10.3,<4.0.0)
|
|
17
|
+
Requires-Dist: numpy (>=2.4.4,<3.0.0)
|
|
18
|
+
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
|
|
19
|
+
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
|
20
|
+
Requires-Dist: plotly (>=6.1.1,<7.0.0)
|
|
21
|
+
Requires-Dist: polymetrix (>=0.2.0,<0.3.0)
|
|
22
|
+
Requires-Dist: pydantic (>=2.12.3,<3.0.0)
|
|
23
|
+
Requires-Dist: ray (>=2.51.0,<3.0.0)
|
|
24
|
+
Requires-Dist: rdkit (>=2025.3.2,<2026.0.0)
|
|
25
|
+
Requires-Dist: scikit-learn (>=1.6.1,<2.0.0)
|
|
26
|
+
Requires-Dist: scipy (>=1.15.3,<2.0.0)
|
|
27
|
+
Requires-Dist: seaborn (>=0.13.2,<0.14.0)
|
|
28
|
+
Requires-Dist: sentence-transformers (>=5.2.3,<6.0.0)
|
|
29
|
+
Requires-Dist: shap (>=0.51.0,<0.52.0)
|
|
30
|
+
Requires-Dist: statsmodels (>=0.14.5,<0.15.0)
|
|
31
|
+
Requires-Dist: streamlit (>=1.45.1,<2.0.0)
|
|
32
|
+
Requires-Dist: torch (==2.2.0) ; sys_platform == "darwin" and platform_machine == "x86_64"
|
|
33
|
+
Requires-Dist: torch (>=2.5.1,<3.0.0) ; sys_platform != "darwin" or platform_machine != "x86_64"
|
|
34
|
+
Requires-Dist: torch-geometric (==2.7)
|
|
35
|
+
Requires-Dist: xgboost (>=3.0.2,<4.0.0)
|
|
36
|
+
Project-URL: Changelog, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CHANGELOG.md
|
|
37
|
+
Project-URL: Documentation, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/tree/main/docs
|
|
38
|
+
Project-URL: Repository, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# PolyNet
|
|
42
|
+
|
|
43
|
+
[](https://www.python.org/)
|
|
44
|
+
[](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/LICENSE)
|
|
45
|
+
[](https://pytorch.org/)
|
|
46
|
+
[](https://pytorch-geometric.readthedocs.io/)
|
|
47
|
+
[](https://www.rdkit.org/)
|
|
48
|
+
[](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/actions/workflows/tests.yml)
|
|
49
|
+
[](https://doi.org/10.5281/zenodo.23302984)
|
|
50
|
+
[](https://github.com/psf/black)
|
|
51
|
+
[](https://python-poetry.org/)
|
|
52
|
+
[]()
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="https://raw.githubusercontent.com/Biomaterials-for-Medical-Devices-AI/PolyNet/main/polynet/app/static/polynet.png" alt="PolyNet logo" width="400"/>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
**PolyNet** is a Python library for polymer property prediction using graph neural networks (GNNs) and traditional machine learning (TML). It provides a complete, configurable pipeline — from raw SMILES strings to trained models, evaluation metrics, result plots, and atom-level explainability — designed for polymer informatics research.
|
|
59
|
+
|
|
60
|
+
The library is split into two layers:
|
|
61
|
+
|
|
62
|
+
- **Core package (`polynet`)** — pipeline stages, model training/inference, featurisers, config schemas, and path/IO helpers. No Streamlit dependency; importable from any Python script or notebook.
|
|
63
|
+
- **Optional GUI (`polynet.app`)** — a Streamlit web application that wraps the same core stages. Install only when you want an interactive interface.
|
|
64
|
+
|
|
65
|
+
Both entry points call the same underlying functions and produce identical results.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Overview
|
|
70
|
+
|
|
71
|
+
Predicting polymer properties from chemical structure is challenging because polymers are repeating units of one or more monomers combined in varying ratios. PolyNet handles this by representing each polymer as a graph where atoms are nodes, bonds are edges, and per-monomer molar ratios (normalised to sum to 1 across the participating monomers) are encoded as node attributes. This graph is fed into GNN architectures that learn structure–property relationships directly from the molecular graph.
|
|
72
|
+
|
|
73
|
+
PolyNet also supports traditional ML workflows using molecular descriptor vectors (RDKit descriptors, PolyBERT fingerprints, and others), enabling direct comparison between GNN and TML approaches on the same dataset and splits.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Features
|
|
78
|
+
|
|
79
|
+
- **Six GNN architectures** — GCN, GAT, CGCNN, MPNN, GraphSAGE, TransformerGNN — each with regression and classification variants
|
|
80
|
+
- **Traditional ML** — Random Forest, XGBoost, SVM, Logistic Regression, Linear Regression, with optional automatic hyperparameter search (`RandomizedSearchCV` scored by shuffled, user-set k-fold cross-validation)
|
|
81
|
+
- **Molecular fingerprints** — Morgan and RDKit count fingerprints with configurable size and Morgan radius (defaults: 2048 bins, radius 3), alongside RDKit descriptors, PolyBERT and PolyMetriX
|
|
82
|
+
- **Multi-monomer polymers** — handles copolymers with any number of monomers and molar ratios; ratios are normalised per polymer to sum to 1 across the participating monomers (any scale works — fractions, percentages, or arbitrary ratios such as 1:1:2), and ratio-0 monomers are excluded from the graph entirely so homopolymers written as `(monomer, 100/0)` are invariant to the empty SMILES column
|
|
83
|
+
- **Per-monomer pooling** — `PerMonomerPooling` weighting mode pools each monomer's nodes separately and combines them as `Σ wᵢ·pool(monomerᵢ)`, removing the atom-count bias that arises when weighting before pooling on mixed-size copolymers (wD-MPNN-style weighted-mean pooling is also supported)
|
|
84
|
+
- **PSMILES attachment-point handling** — opt-in `IsAttachmentPoint` atom feature strips `*` (wildcard) atoms from the graph and flags the atoms that were attached to them, replacing dangling pseudo-element nodes with an explicit boolean marker
|
|
85
|
+
- **PolyMetriX descriptors** — polymer-aware chemical descriptors (molecular weight, ring counts, TPSA, etc.) computed on the full repeat unit, side chain, or backbone, with configurable aggregation; three modes — `side_chain`, `backbone`, and `polymer` — can be used in any combination
|
|
86
|
+
- **Automatic HPO** — Ray Tune for GNNs with configurable split strategy (cross-validation, holdout, repeated holdout; ASHA early stopping for holdout-based strategies); configurable number of sampled configurations (default 50 for GNNs and traditional ML) and custom search grids — in YAML or the GUI — that override individual parameters of the default grids; results cached per search settings and saved with the experiment
|
|
87
|
+
- **Configurable GNN training** — optimiser (Adam, SGD, RMSprop, Adadelta, Adagrad), learning-rate scheduler (ReduceLROnPlateau, step, multi-step, exponential) and regression loss (RMSE, MSE, MAE), applied identically to final training and HPO
|
|
88
|
+
- **Data splitting with astartes** — train/val/test splits drawn with an [astartes](https://github.com/JacksonBurns/astartes) sampler: random (default), Kennard–Stone, SPXY, k-means or target-property, optionally stratified by class; fingerprint samplers use a ratio-weighted polymer fingerprint (Morgan, RDKit or polyBERT) whose type and settings are chosen for splitting only, and the sampling settings are saved with the experiment
|
|
89
|
+
- **Repeated random splits and ensembles** — configurable number of train/val/test splits (`n_bootstrap_iterations`); predictions on new data are combined across the splits into ensembles per GNN architecture, across all GNNs, and per TML model × representation, reported as mean ± standard deviation (regression) or majority vote with vote fraction (classification), with metrics for each ensemble
|
|
90
|
+
- **Structure validation** — SMILES/PSMILES are validated and canonicalised the same way in the GUI, the CLI and when predicting new data; invalid or missing structures and duplicated sample IDs are reported with examples
|
|
91
|
+
- **Target variable scaling** — six scaling strategies for regression targets (StandardScaler, MinMaxScaler, RobustScaler, Log₁₀, Log(1+y), or none); scaler is fit on the training set only and automatically inverse-transformed before metrics and plots so all results are reported in the original target units
|
|
92
|
+
- **Polymer descriptor fusion** — user-supplied experimental or computed polymer-level features (e.g. molecular weight, chain length) can be concatenated to vectorial descriptor representations and, for GNN models, fused into the graph embedding after pooling so the FFN receives both learned and given features; for GNNs they are scaled with the pipeline's feature scaler, fitted on the training split
|
|
93
|
+
- **GNN fragment-level explainability** — chemistry-masking attribution (substructure masking; Wu et al., *Nat. Commun.* 14, 2585 (2023), [doi:10.1038/s41467-023-38192-3](https://doi.org/10.1038/s41467-023-38192-3)): each fragment's importance is measured as the change in prediction when that fragment is masked from the graph pooling step; fragments come from BRICS or Murcko-scaffold fragmentation and attributions are aggregated per fragment; supports global distribution plots (ridge, bar, strip) and per-molecule attribution heatmaps
|
|
94
|
+
- **TML SHAP explainability** — SHAP-based attribution for all traditional ML models using auto-selected explainers (`TreeExplainer` for RF/XGBoost, `LinearExplainer` for linear models, `KernelExplainer` for SVM); global summaries and per-instance plots are rendered with the native `shap` package (beeswarm / bar / violin and waterfall / force / bar); SHAP values are cached to CSV and reused across runs
|
|
95
|
+
- **Configurable explanation display** — view local explanations averaged across the model ensemble or as one plot per model × molecule, with selectable attribution normalisation (local / per-model / global / none)
|
|
96
|
+
- **Statistical model comparison** — pairwise McNemar (classification) and Wilcoxon signed-rank tests on absolute errors (regression) on the Analyse Results page; metric-level comparison across repeated splits with Wilcoxon or the Nadeau–Bengio corrected resampled t-test; multiple-comparison correction (Holm-Bonferroni, Bonferroni, Benjamini-Hochberg)
|
|
97
|
+
- **Publication-quality plots** — parity plots, ROC curves, confusion matrices, learning curves, and attribution heatmaps
|
|
98
|
+
- **Single-command pipeline** — YAML config file drives the entire workflow; no code changes between experiments
|
|
99
|
+
- **GUI-independent core** — all pipeline stages are importable from `polynet` without Streamlit
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Installation
|
|
104
|
+
|
|
105
|
+
PolyNet requires **Python 3.11** and uses [Poetry](https://python-poetry.org/) for dependency management.
|
|
106
|
+
|
|
107
|
+
### Step 1 — Clone the repository
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
git clone https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet.git
|
|
111
|
+
cd PolyNet
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Step 2 — Create a Python 3.11 environment
|
|
115
|
+
|
|
116
|
+
Choose either option.
|
|
117
|
+
|
|
118
|
+
**Option A — conda**
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
conda create -n polynet python=3.11
|
|
122
|
+
conda activate polynet
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Option B — venv**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
python3.11 -m venv .venv
|
|
129
|
+
source .venv/bin/activate # macOS / Linux
|
|
130
|
+
.venv\Scripts\activate # Windows
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Step 3 — Install Poetry
|
|
134
|
+
|
|
135
|
+
With the environment active, install Poetry via pip:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install poetry
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Then tell Poetry to use the active environment rather than creating its own:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
poetry config virtualenvs.create false --local
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Step 4 — Install the project
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
poetry install
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Poetry reads `pyproject.toml` and `poetry.lock` and installs all dependencies into the active environment.
|
|
154
|
+
|
|
155
|
+
### PSMILES support
|
|
156
|
+
|
|
157
|
+
PolyNet canonicalises PSMILES (polymer SMILES with `*` attachment points) with
|
|
158
|
+
[canonicalize-psmiles](https://github.com/kuennethgroup/canonicalize_psmiles) from the
|
|
159
|
+
Kuenneth group. It is distributed by Georgia Tech Research Corporation under its own
|
|
160
|
+
licence, which allows **non-commercial use only**, and is not on PyPI, so it is installed
|
|
161
|
+
separately from PolyNet's MIT-licensed code:
|
|
162
|
+
|
|
163
|
+
- `poetry install` (above) installs it.
|
|
164
|
+
- In the GUI, loading PSMILES data offers an **Install canonicalize-psmiles** button
|
|
165
|
+
after you accept its licence.
|
|
166
|
+
- From a terminal: `polynet install-psmiles`.
|
|
167
|
+
|
|
168
|
+
Datasets written as plain SMILES do not need it.
|
|
169
|
+
|
|
170
|
+
### Verifying the installation
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
polynet check
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This runs the whole pipeline on a small synthetic dataset (about a minute) and prints a PASS / FAIL table.
|
|
177
|
+
|
|
178
|
+
### Common Poetry commands
|
|
179
|
+
|
|
180
|
+
| Command | Description |
|
|
181
|
+
|---|---|
|
|
182
|
+
| `poetry install` | Install all dependencies from `poetry.lock` |
|
|
183
|
+
| `poetry add <package>` | Add a new dependency |
|
|
184
|
+
| `poetry update` | Update all dependencies within the version constraints |
|
|
185
|
+
| `poetry run python <script>` | Run a script without manually activating the environment |
|
|
186
|
+
|
|
187
|
+
**Dependencies** (managed by Poetry): PyTorch, PyTorch Geometric, RDKit, scikit-learn, XGBoost, imbalanced-learn, Ray Tune, Captum, Streamlit, Pydantic, matplotlib, seaborn, scipy, statsmodels, and more — see `pyproject.toml` for the full list.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Quick Start
|
|
192
|
+
|
|
193
|
+
### CLI
|
|
194
|
+
|
|
195
|
+
**1. Edit the config file** to point at your data and choose your models. The template
|
|
196
|
+
`configs/experiment.yaml` runs out of the box on the built-in Tg benchmark
|
|
197
|
+
(`benchmark_dataset: "curated_tg"`, downloaded on first use); to use your own data,
|
|
198
|
+
replace it with `data_path`:
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
# configs/experiment.yaml
|
|
202
|
+
experiment:
|
|
203
|
+
name: "tg_prediction"
|
|
204
|
+
output_dir: "results/tg_prediction"
|
|
205
|
+
random_seed: 42
|
|
206
|
+
|
|
207
|
+
data:
|
|
208
|
+
data_path: "data/polymers.csv"
|
|
209
|
+
id_col: "polymer_id"
|
|
210
|
+
target_variable_col: "Tg"
|
|
211
|
+
target_variable_name: "Glass Transition Temperature"
|
|
212
|
+
problem_type: "regression"
|
|
213
|
+
smiles_cols:
|
|
214
|
+
- "monomer1_smiles"
|
|
215
|
+
- "monomer2_smiles"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**2. Run the pipeline:**
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
polynet run --config configs/experiment.yaml
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
All outputs are written to the directory specified by `experiment.output_dir` in the config. `polynet run --help` lists the flags (e.g. `--epochs`, `--no-gnn`, `--predict-data`).
|
|
225
|
+
|
|
226
|
+
### Streamlit GUI
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
polynet
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
This works from any directory once the package is installed (`polynet gui` is the same). Any `streamlit run` option is forwarded, so `polynet --server.port 8502` changes the port. When developing PolyNet, run `polynet --server.fileWatcherType auto` so the app reloads on save (see [Development](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md#running-the-gui-while-developing)). From the repository root, the explicit command also works:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
streamlit run polynet/app/Welcome_to_PolyNet.py
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Python API
|
|
239
|
+
|
|
240
|
+
The core stages can be called directly from any script or notebook:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from polynet.pipeline import (
|
|
244
|
+
build_graph_dataset,
|
|
245
|
+
compute_descriptors,
|
|
246
|
+
compute_data_splits,
|
|
247
|
+
train_gnn,
|
|
248
|
+
run_gnn_inference,
|
|
249
|
+
train_tml,
|
|
250
|
+
run_tml_inference,
|
|
251
|
+
compute_metrics,
|
|
252
|
+
predict_external,
|
|
253
|
+
)
|
|
254
|
+
from polynet.config.io import save_options, load_options
|
|
255
|
+
from polynet.config.paths import polynet_experiments_base_dir, model_dir
|
|
256
|
+
from polynet.experiment.manager import get_experiments, create_experiment
|
|
257
|
+
from polynet.models.persistence import load_models_from_experiment
|
|
258
|
+
from polynet.inference.predict import predict_unseen_tml, predict_unseen_gnn
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Data Format
|
|
264
|
+
|
|
265
|
+
PolyNet expects a CSV file with one row per polymer sample:
|
|
266
|
+
|
|
267
|
+
| Column | Required | Description |
|
|
268
|
+
|--------|----------|-------------|
|
|
269
|
+
| `polymer_id` | Recommended | Unique identifier (used as sample index) |
|
|
270
|
+
| `monomer1_smiles` | Yes | SMILES string for the first monomer |
|
|
271
|
+
| `monomer2_smiles` | Yes (copolymers) | SMILES string for the second monomer |
|
|
272
|
+
| `ratio_1` | No | Molar ratio of monomer 1. Omit to treat monomers as equally weighted |
|
|
273
|
+
| `ratio_2` | No | Molar ratio of monomer 2 |
|
|
274
|
+
| `target` | Yes | Property to predict (numeric for regression, integer class for classification) |
|
|
275
|
+
|
|
276
|
+
Copolymers with any number of monomers are supported by adding one SMILES column and one molar-ratio column per monomer and listing them in the config. Ratios are normalised per polymer to sum to 1 across the participating monomers, so they need not sum to 1 or 100; a ratio of 0 excludes that monomer. The target column is optional when predicting on unseen data.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Documentation
|
|
281
|
+
|
|
282
|
+
Full documentation lives in [`docs/`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/README.md):
|
|
283
|
+
|
|
284
|
+
- **[Configuration reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/configuration.md)** — every YAML section, including automatic HPO
|
|
285
|
+
- **[Descriptors](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/descriptors.md)** — polymer descriptor fusion and the PolyMetriX integration
|
|
286
|
+
- **[Explainability](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/explainability.md)** — GNN masking & TML SHAP attribution, normalisation, averaged vs per-model display, and statistical model comparison
|
|
287
|
+
- **[Running the pipeline & outputs](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/running-and-outputs.md)** — CLI flags, predicting on external data, target scaling, and the output directory layout
|
|
288
|
+
- **[API reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/api-reference.md)** — project structure and the public Python API
|
|
289
|
+
- **[GUI & architecture](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/gui-and-architecture.md)** — the Streamlit application and the core-vs-GUI design
|
|
290
|
+
- **[Development](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md)** — running the test suite and extending PolyNet
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Team
|
|
295
|
+
- [Eduardo Aguilar](https://edaguilarb.github.io./) (Chemist, Data Scientist, Research Software Engineer)
|
|
296
|
+
- [David Winkler](https://scholar.google.com/citations?user=P8DvrTgAAAAJ&hl=en) (Professor, Cheminformatician)
|
|
297
|
+
- [Grazziela Figueredo](https://scholar.google.com/citations?user=DXNNUcUAAAAJ&hl=en) (Associate Professor, Data Scientist, Product Owner, Principal Investigator)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
## Citing PolyNet
|
|
301
|
+
|
|
302
|
+
If you use PolyNet, please cite the software (GitHub's "Cite this repository" button reads [`CITATION.cff`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CITATION.cff)):
|
|
303
|
+
|
|
304
|
+
```bibtex
|
|
305
|
+
@software{polynet,
|
|
306
|
+
author = {Aguilar-Bejarano, Eduardo and Alexander, Morgan and Winkler, David and Figueredo, Grazziela},
|
|
307
|
+
title = {PolyNet: A Python Package for Polymer Informatics},
|
|
308
|
+
version = {1.0.1},
|
|
309
|
+
year = {2026},
|
|
310
|
+
doi = {10.5281/zenodo.23302984},
|
|
311
|
+
url = {https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet}
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
This DOI always resolves to the latest release. To cite the exact version you used,
|
|
316
|
+
take its DOI from the [Zenodo record](https://doi.org/10.5281/zenodo.23302984)
|
|
317
|
+
(1.0.0: [10.5281/zenodo.23302985](https://doi.org/10.5281/zenodo.23302985)).
|
|
318
|
+
|
|
319
|
+
Changes between versions are listed in [`CHANGELOG.md`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CHANGELOG.md).
|
|
320
|
+
|
polynet-1.0.1/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# PolyNet
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org/)
|
|
4
|
+
[](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/LICENSE)
|
|
5
|
+
[](https://pytorch.org/)
|
|
6
|
+
[](https://pytorch-geometric.readthedocs.io/)
|
|
7
|
+
[](https://www.rdkit.org/)
|
|
8
|
+
[](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/actions/workflows/tests.yml)
|
|
9
|
+
[](https://doi.org/10.5281/zenodo.23302984)
|
|
10
|
+
[](https://github.com/psf/black)
|
|
11
|
+
[](https://python-poetry.org/)
|
|
12
|
+
[]()
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="https://raw.githubusercontent.com/Biomaterials-for-Medical-Devices-AI/PolyNet/main/polynet/app/static/polynet.png" alt="PolyNet logo" width="400"/>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
**PolyNet** is a Python library for polymer property prediction using graph neural networks (GNNs) and traditional machine learning (TML). It provides a complete, configurable pipeline — from raw SMILES strings to trained models, evaluation metrics, result plots, and atom-level explainability — designed for polymer informatics research.
|
|
19
|
+
|
|
20
|
+
The library is split into two layers:
|
|
21
|
+
|
|
22
|
+
- **Core package (`polynet`)** — pipeline stages, model training/inference, featurisers, config schemas, and path/IO helpers. No Streamlit dependency; importable from any Python script or notebook.
|
|
23
|
+
- **Optional GUI (`polynet.app`)** — a Streamlit web application that wraps the same core stages. Install only when you want an interactive interface.
|
|
24
|
+
|
|
25
|
+
Both entry points call the same underlying functions and produce identical results.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
Predicting polymer properties from chemical structure is challenging because polymers are repeating units of one or more monomers combined in varying ratios. PolyNet handles this by representing each polymer as a graph where atoms are nodes, bonds are edges, and per-monomer molar ratios (normalised to sum to 1 across the participating monomers) are encoded as node attributes. This graph is fed into GNN architectures that learn structure–property relationships directly from the molecular graph.
|
|
32
|
+
|
|
33
|
+
PolyNet also supports traditional ML workflows using molecular descriptor vectors (RDKit descriptors, PolyBERT fingerprints, and others), enabling direct comparison between GNN and TML approaches on the same dataset and splits.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- **Six GNN architectures** — GCN, GAT, CGCNN, MPNN, GraphSAGE, TransformerGNN — each with regression and classification variants
|
|
40
|
+
- **Traditional ML** — Random Forest, XGBoost, SVM, Logistic Regression, Linear Regression, with optional automatic hyperparameter search (`RandomizedSearchCV` scored by shuffled, user-set k-fold cross-validation)
|
|
41
|
+
- **Molecular fingerprints** — Morgan and RDKit count fingerprints with configurable size and Morgan radius (defaults: 2048 bins, radius 3), alongside RDKit descriptors, PolyBERT and PolyMetriX
|
|
42
|
+
- **Multi-monomer polymers** — handles copolymers with any number of monomers and molar ratios; ratios are normalised per polymer to sum to 1 across the participating monomers (any scale works — fractions, percentages, or arbitrary ratios such as 1:1:2), and ratio-0 monomers are excluded from the graph entirely so homopolymers written as `(monomer, 100/0)` are invariant to the empty SMILES column
|
|
43
|
+
- **Per-monomer pooling** — `PerMonomerPooling` weighting mode pools each monomer's nodes separately and combines them as `Σ wᵢ·pool(monomerᵢ)`, removing the atom-count bias that arises when weighting before pooling on mixed-size copolymers (wD-MPNN-style weighted-mean pooling is also supported)
|
|
44
|
+
- **PSMILES attachment-point handling** — opt-in `IsAttachmentPoint` atom feature strips `*` (wildcard) atoms from the graph and flags the atoms that were attached to them, replacing dangling pseudo-element nodes with an explicit boolean marker
|
|
45
|
+
- **PolyMetriX descriptors** — polymer-aware chemical descriptors (molecular weight, ring counts, TPSA, etc.) computed on the full repeat unit, side chain, or backbone, with configurable aggregation; three modes — `side_chain`, `backbone`, and `polymer` — can be used in any combination
|
|
46
|
+
- **Automatic HPO** — Ray Tune for GNNs with configurable split strategy (cross-validation, holdout, repeated holdout; ASHA early stopping for holdout-based strategies); configurable number of sampled configurations (default 50 for GNNs and traditional ML) and custom search grids — in YAML or the GUI — that override individual parameters of the default grids; results cached per search settings and saved with the experiment
|
|
47
|
+
- **Configurable GNN training** — optimiser (Adam, SGD, RMSprop, Adadelta, Adagrad), learning-rate scheduler (ReduceLROnPlateau, step, multi-step, exponential) and regression loss (RMSE, MSE, MAE), applied identically to final training and HPO
|
|
48
|
+
- **Data splitting with astartes** — train/val/test splits drawn with an [astartes](https://github.com/JacksonBurns/astartes) sampler: random (default), Kennard–Stone, SPXY, k-means or target-property, optionally stratified by class; fingerprint samplers use a ratio-weighted polymer fingerprint (Morgan, RDKit or polyBERT) whose type and settings are chosen for splitting only, and the sampling settings are saved with the experiment
|
|
49
|
+
- **Repeated random splits and ensembles** — configurable number of train/val/test splits (`n_bootstrap_iterations`); predictions on new data are combined across the splits into ensembles per GNN architecture, across all GNNs, and per TML model × representation, reported as mean ± standard deviation (regression) or majority vote with vote fraction (classification), with metrics for each ensemble
|
|
50
|
+
- **Structure validation** — SMILES/PSMILES are validated and canonicalised the same way in the GUI, the CLI and when predicting new data; invalid or missing structures and duplicated sample IDs are reported with examples
|
|
51
|
+
- **Target variable scaling** — six scaling strategies for regression targets (StandardScaler, MinMaxScaler, RobustScaler, Log₁₀, Log(1+y), or none); scaler is fit on the training set only and automatically inverse-transformed before metrics and plots so all results are reported in the original target units
|
|
52
|
+
- **Polymer descriptor fusion** — user-supplied experimental or computed polymer-level features (e.g. molecular weight, chain length) can be concatenated to vectorial descriptor representations and, for GNN models, fused into the graph embedding after pooling so the FFN receives both learned and given features; for GNNs they are scaled with the pipeline's feature scaler, fitted on the training split
|
|
53
|
+
- **GNN fragment-level explainability** — chemistry-masking attribution (substructure masking; Wu et al., *Nat. Commun.* 14, 2585 (2023), [doi:10.1038/s41467-023-38192-3](https://doi.org/10.1038/s41467-023-38192-3)): each fragment's importance is measured as the change in prediction when that fragment is masked from the graph pooling step; fragments come from BRICS or Murcko-scaffold fragmentation and attributions are aggregated per fragment; supports global distribution plots (ridge, bar, strip) and per-molecule attribution heatmaps
|
|
54
|
+
- **TML SHAP explainability** — SHAP-based attribution for all traditional ML models using auto-selected explainers (`TreeExplainer` for RF/XGBoost, `LinearExplainer` for linear models, `KernelExplainer` for SVM); global summaries and per-instance plots are rendered with the native `shap` package (beeswarm / bar / violin and waterfall / force / bar); SHAP values are cached to CSV and reused across runs
|
|
55
|
+
- **Configurable explanation display** — view local explanations averaged across the model ensemble or as one plot per model × molecule, with selectable attribution normalisation (local / per-model / global / none)
|
|
56
|
+
- **Statistical model comparison** — pairwise McNemar (classification) and Wilcoxon signed-rank tests on absolute errors (regression) on the Analyse Results page; metric-level comparison across repeated splits with Wilcoxon or the Nadeau–Bengio corrected resampled t-test; multiple-comparison correction (Holm-Bonferroni, Bonferroni, Benjamini-Hochberg)
|
|
57
|
+
- **Publication-quality plots** — parity plots, ROC curves, confusion matrices, learning curves, and attribution heatmaps
|
|
58
|
+
- **Single-command pipeline** — YAML config file drives the entire workflow; no code changes between experiments
|
|
59
|
+
- **GUI-independent core** — all pipeline stages are importable from `polynet` without Streamlit
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
PolyNet requires **Python 3.11** and uses [Poetry](https://python-poetry.org/) for dependency management.
|
|
66
|
+
|
|
67
|
+
### Step 1 — Clone the repository
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
git clone https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet.git
|
|
71
|
+
cd PolyNet
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Step 2 — Create a Python 3.11 environment
|
|
75
|
+
|
|
76
|
+
Choose either option.
|
|
77
|
+
|
|
78
|
+
**Option A — conda**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
conda create -n polynet python=3.11
|
|
82
|
+
conda activate polynet
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Option B — venv**
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
python3.11 -m venv .venv
|
|
89
|
+
source .venv/bin/activate # macOS / Linux
|
|
90
|
+
.venv\Scripts\activate # Windows
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Step 3 — Install Poetry
|
|
94
|
+
|
|
95
|
+
With the environment active, install Poetry via pip:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install poetry
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Then tell Poetry to use the active environment rather than creating its own:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
poetry config virtualenvs.create false --local
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Step 4 — Install the project
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
poetry install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Poetry reads `pyproject.toml` and `poetry.lock` and installs all dependencies into the active environment.
|
|
114
|
+
|
|
115
|
+
### PSMILES support
|
|
116
|
+
|
|
117
|
+
PolyNet canonicalises PSMILES (polymer SMILES with `*` attachment points) with
|
|
118
|
+
[canonicalize-psmiles](https://github.com/kuennethgroup/canonicalize_psmiles) from the
|
|
119
|
+
Kuenneth group. It is distributed by Georgia Tech Research Corporation under its own
|
|
120
|
+
licence, which allows **non-commercial use only**, and is not on PyPI, so it is installed
|
|
121
|
+
separately from PolyNet's MIT-licensed code:
|
|
122
|
+
|
|
123
|
+
- `poetry install` (above) installs it.
|
|
124
|
+
- In the GUI, loading PSMILES data offers an **Install canonicalize-psmiles** button
|
|
125
|
+
after you accept its licence.
|
|
126
|
+
- From a terminal: `polynet install-psmiles`.
|
|
127
|
+
|
|
128
|
+
Datasets written as plain SMILES do not need it.
|
|
129
|
+
|
|
130
|
+
### Verifying the installation
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
polynet check
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
This runs the whole pipeline on a small synthetic dataset (about a minute) and prints a PASS / FAIL table.
|
|
137
|
+
|
|
138
|
+
### Common Poetry commands
|
|
139
|
+
|
|
140
|
+
| Command | Description |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `poetry install` | Install all dependencies from `poetry.lock` |
|
|
143
|
+
| `poetry add <package>` | Add a new dependency |
|
|
144
|
+
| `poetry update` | Update all dependencies within the version constraints |
|
|
145
|
+
| `poetry run python <script>` | Run a script without manually activating the environment |
|
|
146
|
+
|
|
147
|
+
**Dependencies** (managed by Poetry): PyTorch, PyTorch Geometric, RDKit, scikit-learn, XGBoost, imbalanced-learn, Ray Tune, Captum, Streamlit, Pydantic, matplotlib, seaborn, scipy, statsmodels, and more — see `pyproject.toml` for the full list.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Quick Start
|
|
152
|
+
|
|
153
|
+
### CLI
|
|
154
|
+
|
|
155
|
+
**1. Edit the config file** to point at your data and choose your models. The template
|
|
156
|
+
`configs/experiment.yaml` runs out of the box on the built-in Tg benchmark
|
|
157
|
+
(`benchmark_dataset: "curated_tg"`, downloaded on first use); to use your own data,
|
|
158
|
+
replace it with `data_path`:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
# configs/experiment.yaml
|
|
162
|
+
experiment:
|
|
163
|
+
name: "tg_prediction"
|
|
164
|
+
output_dir: "results/tg_prediction"
|
|
165
|
+
random_seed: 42
|
|
166
|
+
|
|
167
|
+
data:
|
|
168
|
+
data_path: "data/polymers.csv"
|
|
169
|
+
id_col: "polymer_id"
|
|
170
|
+
target_variable_col: "Tg"
|
|
171
|
+
target_variable_name: "Glass Transition Temperature"
|
|
172
|
+
problem_type: "regression"
|
|
173
|
+
smiles_cols:
|
|
174
|
+
- "monomer1_smiles"
|
|
175
|
+
- "monomer2_smiles"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**2. Run the pipeline:**
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
polynet run --config configs/experiment.yaml
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
All outputs are written to the directory specified by `experiment.output_dir` in the config. `polynet run --help` lists the flags (e.g. `--epochs`, `--no-gnn`, `--predict-data`).
|
|
185
|
+
|
|
186
|
+
### Streamlit GUI
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
polynet
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
This works from any directory once the package is installed (`polynet gui` is the same). Any `streamlit run` option is forwarded, so `polynet --server.port 8502` changes the port. When developing PolyNet, run `polynet --server.fileWatcherType auto` so the app reloads on save (see [Development](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md#running-the-gui-while-developing)). From the repository root, the explicit command also works:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
streamlit run polynet/app/Welcome_to_PolyNet.py
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Python API
|
|
199
|
+
|
|
200
|
+
The core stages can be called directly from any script or notebook:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from polynet.pipeline import (
|
|
204
|
+
build_graph_dataset,
|
|
205
|
+
compute_descriptors,
|
|
206
|
+
compute_data_splits,
|
|
207
|
+
train_gnn,
|
|
208
|
+
run_gnn_inference,
|
|
209
|
+
train_tml,
|
|
210
|
+
run_tml_inference,
|
|
211
|
+
compute_metrics,
|
|
212
|
+
predict_external,
|
|
213
|
+
)
|
|
214
|
+
from polynet.config.io import save_options, load_options
|
|
215
|
+
from polynet.config.paths import polynet_experiments_base_dir, model_dir
|
|
216
|
+
from polynet.experiment.manager import get_experiments, create_experiment
|
|
217
|
+
from polynet.models.persistence import load_models_from_experiment
|
|
218
|
+
from polynet.inference.predict import predict_unseen_tml, predict_unseen_gnn
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Data Format
|
|
224
|
+
|
|
225
|
+
PolyNet expects a CSV file with one row per polymer sample:
|
|
226
|
+
|
|
227
|
+
| Column | Required | Description |
|
|
228
|
+
|--------|----------|-------------|
|
|
229
|
+
| `polymer_id` | Recommended | Unique identifier (used as sample index) |
|
|
230
|
+
| `monomer1_smiles` | Yes | SMILES string for the first monomer |
|
|
231
|
+
| `monomer2_smiles` | Yes (copolymers) | SMILES string for the second monomer |
|
|
232
|
+
| `ratio_1` | No | Molar ratio of monomer 1. Omit to treat monomers as equally weighted |
|
|
233
|
+
| `ratio_2` | No | Molar ratio of monomer 2 |
|
|
234
|
+
| `target` | Yes | Property to predict (numeric for regression, integer class for classification) |
|
|
235
|
+
|
|
236
|
+
Copolymers with any number of monomers are supported by adding one SMILES column and one molar-ratio column per monomer and listing them in the config. Ratios are normalised per polymer to sum to 1 across the participating monomers, so they need not sum to 1 or 100; a ratio of 0 excludes that monomer. The target column is optional when predicting on unseen data.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Documentation
|
|
241
|
+
|
|
242
|
+
Full documentation lives in [`docs/`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/README.md):
|
|
243
|
+
|
|
244
|
+
- **[Configuration reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/configuration.md)** — every YAML section, including automatic HPO
|
|
245
|
+
- **[Descriptors](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/descriptors.md)** — polymer descriptor fusion and the PolyMetriX integration
|
|
246
|
+
- **[Explainability](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/explainability.md)** — GNN masking & TML SHAP attribution, normalisation, averaged vs per-model display, and statistical model comparison
|
|
247
|
+
- **[Running the pipeline & outputs](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/running-and-outputs.md)** — CLI flags, predicting on external data, target scaling, and the output directory layout
|
|
248
|
+
- **[API reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/api-reference.md)** — project structure and the public Python API
|
|
249
|
+
- **[GUI & architecture](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/gui-and-architecture.md)** — the Streamlit application and the core-vs-GUI design
|
|
250
|
+
- **[Development](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md)** — running the test suite and extending PolyNet
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Team
|
|
255
|
+
- [Eduardo Aguilar](https://edaguilarb.github.io./) (Chemist, Data Scientist, Research Software Engineer)
|
|
256
|
+
- [David Winkler](https://scholar.google.com/citations?user=P8DvrTgAAAAJ&hl=en) (Professor, Cheminformatician)
|
|
257
|
+
- [Grazziela Figueredo](https://scholar.google.com/citations?user=DXNNUcUAAAAJ&hl=en) (Associate Professor, Data Scientist, Product Owner, Principal Investigator)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
## Citing PolyNet
|
|
261
|
+
|
|
262
|
+
If you use PolyNet, please cite the software (GitHub's "Cite this repository" button reads [`CITATION.cff`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CITATION.cff)):
|
|
263
|
+
|
|
264
|
+
```bibtex
|
|
265
|
+
@software{polynet,
|
|
266
|
+
author = {Aguilar-Bejarano, Eduardo and Alexander, Morgan and Winkler, David and Figueredo, Grazziela},
|
|
267
|
+
title = {PolyNet: A Python Package for Polymer Informatics},
|
|
268
|
+
version = {1.0.1},
|
|
269
|
+
year = {2026},
|
|
270
|
+
doi = {10.5281/zenodo.23302984},
|
|
271
|
+
url = {https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
This DOI always resolves to the latest release. To cite the exact version you used,
|
|
276
|
+
take its DOI from the [Zenodo record](https://doi.org/10.5281/zenodo.23302984)
|
|
277
|
+
(1.0.0: [10.5281/zenodo.23302985](https://doi.org/10.5281/zenodo.23302985)).
|
|
278
|
+
|
|
279
|
+
Changes between versions are listed in [`CHANGELOG.md`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CHANGELOG.md).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""PolyNet: polymer property prediction with GNNs and traditional ML."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("polynet")
|
|
7
|
+
except PackageNotFoundError: # running from a source tree that is not installed
|
|
8
|
+
__version__ = "unknown"
|