Metadata-Version: 2.4
Name: polynet
Version: 1.0.3
Summary: A Python package for polymer informatics: property prediction with graph neural networks and traditional machine learning
License-Expression: MIT
License-File: LICENSE
Keywords: polymer informatics,graph neural networks,machine learning,explainability
Author: Eduardo Aguilar-Bejarano
Author-email: eduardo.aguilar-bejarano@nottingham.ac.uk
Requires-Python: >=3.11,<3.12
Classifier: Programming Language :: Python :: 3.11
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Chemistry
Requires-Dist: astartes (>=1.3.3,<2.0.0)
Requires-Dist: imbalanced-learn (>=0.14.0,<0.15.0)
Requires-Dist: matplotlib (>=3.10.3,<4.0.0)
Requires-Dist: numpy (>=2.4.4,<3.0.0)
Requires-Dist: openpyxl (>=3.1.5,<4.0.0)
Requires-Dist: pandas (>=2.2.3,<3.0.0)
Requires-Dist: plotly (>=6.1.1,<7.0.0)
Requires-Dist: polymetrix (>=0.2.0,<0.3.0)
Requires-Dist: pydantic (>=2.12.3,<3.0.0)
Requires-Dist: ray (>=2.51.0,<3.0.0)
Requires-Dist: rdkit (>=2025.3.2,<2026.0.0)
Requires-Dist: scikit-learn (>=1.6.1,<2.0.0)
Requires-Dist: scipy (>=1.15.3,<2.0.0)
Requires-Dist: seaborn (>=0.13.2,<0.14.0)
Requires-Dist: sentence-transformers (>=5.2.3,<6.0.0)
Requires-Dist: shap (>=0.51.0,<0.52.0)
Requires-Dist: statsmodels (>=0.14.5,<0.15.0)
Requires-Dist: streamlit (>=1.45.1,<2.0.0)
Requires-Dist: torch (==2.2.0) ; sys_platform == "darwin" and platform_machine == "x86_64"
Requires-Dist: torch (>=2.5.1,<2.11) ; sys_platform == "darwin" and platform_machine == "arm64"
Requires-Dist: torch (>=2.5.1,<3.0.0) ; sys_platform != "darwin"
Requires-Dist: torch-geometric (==2.7)
Requires-Dist: xgboost (>=3.0.2,<4.0.0)
Project-URL: Changelog, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/tree/main/docs
Project-URL: Repository, https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet
Description-Content-Type: text/markdown

# PolyNet

[![Python](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/LICENSE)
[![PyTorch](https://img.shields.io/badge/PyTorch-2.x-ee4c2c?logo=pytorch&logoColor=white)](https://pytorch.org/)
[![PyG](https://img.shields.io/badge/PyTorch%20Geometric-enabled-3C2179)](https://pytorch-geometric.readthedocs.io/)
[![RDKit](https://img.shields.io/badge/RDKit-supported-informational)](https://www.rdkit.org/)
[![Tests](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/actions/workflows/tests.yml/badge.svg)](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/actions/workflows/tests.yml)
[![PyPI](https://img.shields.io/pypi/v/polynet.svg)](https://pypi.org/project/polynet/)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23302984.svg)](https://doi.org/10.5281/zenodo.23302984)
[![Black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Poetry](https://img.shields.io/badge/dependency%20management-poetry-60A5FA)](https://python-poetry.org/)
[![Status](https://img.shields.io/badge/status-active%20development-brightgreen)]()

<p align="center">
  <img src="https://raw.githubusercontent.com/Biomaterials-for-Medical-Devices-AI/PolyNet/main/polynet/app/static/polynet.png" alt="PolyNet logo" width="400"/>
</p>

**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.

The library is split into two layers:

- **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.
- **Optional GUI (`polynet.app`)** — a Streamlit web application that wraps the same core stages. Install only when you want an interactive interface.

Both entry points call the same underlying functions and produce identical results.

---

## Overview

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.

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.

---

## Features

- **Six GNN architectures** — GCN, GAT, CGCNN, MPNN, GraphSAGE, TransformerGNN — each with regression and classification variants
- **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)
- **Molecular fingerprints** — Morgan and RDKit count fingerprints with configurable size and Morgan radius (defaults: 2048 bins, radius 3), alongside RDKit descriptors, PolyBERT and PolyMetriX
- **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
- **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)
- **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
- **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
- **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
- **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
- **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
- **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
- **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
- **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
- **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
- **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
- **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
- **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)
- **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)
- **Publication-quality plots** — parity plots, ROC curves, confusion matrices, learning curves, and attribution heatmaps
- **Single-command pipeline** — YAML config file drives the entire workflow; no code changes between experiments
- **GUI-independent core** — all pipeline stages are importable from `polynet` without Streamlit

---

## Installation

PolyNet requires **Python 3.11**. Install it from PyPI to use it, or from source with
[Poetry](https://python-poetry.org/) to develop it.

### Option 1 — From PyPI (recommended)

Create a Python 3.11 environment with conda:

```bash
conda create -n polynet python=3.11
conda activate polynet
```

or with venv:

```bash
python3.11 -m venv .venv
source .venv/bin/activate      # macOS / Linux
.venv\Scripts\activate         # Windows
```

Then install PolyNet:

```bash
pip install polynet
```

On macOS, XGBoost also needs the OpenMP library from [Homebrew](https://brew.sh):
`brew install libomp`.

This installs the `polynet` command: `polynet` opens the GUI and `polynet run --config
experiment.yaml` runs the pipeline (see Quick Start below).

### Option 2 — From source with Poetry (development)

#### Step 1 — Clone the repository

```bash
git clone https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet.git
cd PolyNet
```

#### Step 2 — Create a Python 3.11 environment

As in Option 1 (conda or venv).

#### Step 3 — Install Poetry

With the environment active, install Poetry via pip:

```bash
pip install poetry
```

Then tell Poetry to use the active environment rather than creating its own:

```bash
poetry config virtualenvs.create false --local
```

#### Step 4 — Install the project

```bash
poetry install
```

Poetry reads `pyproject.toml` and `poetry.lock` and installs the exact dependency versions
the project is developed and tested with, plus the development tools. `pip install polynet`
instead takes the newest versions `pyproject.toml` allows. When developing the GUI, see
[Running the GUI while developing](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md#running-the-gui-while-developing).

### PSMILES support

PolyNet canonicalises PSMILES (polymer SMILES with `*` attachment points) with
[canonicalize-psmiles](https://github.com/kuennethgroup/canonicalize_psmiles) from the
Kuenneth group. It is distributed by Georgia Tech Research Corporation under its own
licence, which allows **non-commercial use only**, and is not on PyPI, so it is installed
separately from PolyNet's MIT-licensed code:

- `poetry install` (Option 2) installs it; `pip install polynet` does not.
- In the GUI, loading PSMILES data offers an **Install canonicalize-psmiles** button
  after you accept its licence.
- From a terminal: `polynet install-psmiles`.

Datasets written as plain SMILES do not need it.

### Verifying the installation

```bash
polynet check
```

This runs the whole pipeline on a small synthetic dataset (about a minute) and prints a PASS / FAIL table.

### Common Poetry commands

| Command | Description |
|---|---|
| `poetry install` | Install all dependencies from `poetry.lock` |
| `poetry add <package>` | Add a new dependency |
| `poetry update` | Update all dependencies within the version constraints |
| `poetry run python <script>` | Run a script without manually activating the environment |

**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.

---

## Quick Start

### CLI

**1. Edit the config file** to point at your data and choose your models. The template
`configs/experiment.yaml` runs out of the box on the built-in Tg benchmark
(`benchmark_dataset: "curated_tg"`, downloaded on first use); to use your own data,
replace it with `data_path`. If you installed from PyPI, download the template from
[GitHub](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/configs/experiment.yaml):

```yaml
# configs/experiment.yaml
experiment:
  name: "tg_prediction"
  output_dir: "results/tg_prediction"
  random_seed: 42

data:
  data_path: "data/polymers.csv"
  id_col: "polymer_id"
  target_variable_col: "Tg"
  target_variable_name: "Glass Transition Temperature"
  problem_type: "regression"
  smiles_cols:
    - "monomer1_smiles"
    - "monomer2_smiles"
```

**2. Run the pipeline:**

```bash
polynet run --config configs/experiment.yaml
```

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`).

### Streamlit GUI

```bash
polynet
```

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:

```bash
streamlit run polynet/app/Welcome_to_PolyNet.py
```

### Python API

The core stages can be called directly from any script or notebook:

```python
from polynet.pipeline import (
    build_graph_dataset,
    compute_descriptors,
    compute_data_splits,
    train_gnn,
    run_gnn_inference,
    train_tml,
    run_tml_inference,
    compute_metrics,
    predict_external,
)
from polynet.config.io import save_options, load_options
from polynet.config.paths import polynet_experiments_base_dir, model_dir
from polynet.experiment.manager import get_experiments, create_experiment
from polynet.models.persistence import load_models_from_experiment
from polynet.inference.predict import predict_unseen_tml, predict_unseen_gnn
```

---

## Data Format

PolyNet expects a CSV file with one row per polymer sample:

| Column | Required | Description |
|--------|----------|-------------|
| `polymer_id` | Recommended | Unique identifier (used as sample index) |
| `monomer1_smiles` | Yes | SMILES string for the first monomer |
| `monomer2_smiles` | Yes (copolymers) | SMILES string for the second monomer |
| `ratio_1` | No | Molar ratio of monomer 1. Omit to treat monomers as equally weighted |
| `ratio_2` | No | Molar ratio of monomer 2 |
| `target` | Yes | Property to predict (numeric for regression, integer class for classification) |

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.

---

## Documentation

Full documentation lives in [`docs/`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/README.md):

- **[Configuration reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/configuration.md)** — every YAML section, including automatic HPO
- **[Descriptors](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/descriptors.md)** — polymer descriptor fusion and the PolyMetriX integration
- **[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
- **[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
- **[API reference](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/api-reference.md)** — project structure and the public Python API
- **[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
- **[Development](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/docs/development.md)** — running the test suite and extending PolyNet

---

## Team
- [Eduardo Aguilar](https://edaguilarb.github.io./) (Chemist, Data Scientist, Research Software Engineer)
- [David Winkler](https://scholar.google.com/citations?user=P8DvrTgAAAAJ&hl=en) (Professor, Cheminformatician)
- [Grazziela Figueredo](https://scholar.google.com/citations?user=DXNNUcUAAAAJ&hl=en) (Associate Professor, Data Scientist, Product Owner, Principal Investigator)


## Citing PolyNet

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)):

```bibtex
@software{polynet,
  author  = {Aguilar-Bejarano, Eduardo and Alexander, Morgan and Winkler, David and Figueredo, Grazziela},
  title   = {PolyNet: A Python Package for Polymer Informatics},
  version = {1.0.3},
  year    = {2026},
  doi     = {10.5281/zenodo.23302984},
  url     = {https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet}
}
```

This DOI always resolves to the latest release. To cite the exact version you used,
take its DOI from the [Zenodo record](https://doi.org/10.5281/zenodo.23302984)
(1.0.0: [10.5281/zenodo.23302985](https://doi.org/10.5281/zenodo.23302985)).

Changes between versions are listed in [`CHANGELOG.md`](https://github.com/Biomaterials-for-Medical-Devices-AI/PolyNet/blob/main/CHANGELOG.md).

