PolyNet
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 (
RandomizedSearchCVscored 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 —
PerMonomerPoolingweighting 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
IsAttachmentPointatom 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, andpolymer— 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 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): 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 (
TreeExplainerfor RF/XGBoost,LinearExplainerfor linear models,KernelExplainerfor SVM); global summaries and per-instance plots are rendered with the nativeshappackage (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
polynetwithout Streamlit
Installation
PolyNet requires Python 3.11. Install it from PyPI to use it, or from source with Poetry to develop it.
Option 1 — From PyPI (recommended)
Create a Python 3.11 environment with conda:
conda create -n polynet python=3.11
conda activate polynet
or with venv:
python3.11 -m venv .venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windows
Then install PolyNet:
pip install polynet
On macOS, XGBoost also needs the OpenMP library from Homebrew:
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
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:
pip install poetry
Then tell Poetry to use the active environment rather than creating its own:
poetry config virtualenvs.create false --local
Step 4 — Install the project
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.
PSMILES support
PolyNet canonicalises PSMILES (polymer SMILES with * attachment points) with
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 polynetdoes 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
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:
# 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:
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
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). From the repository root, the explicit command also works:
streamlit run polynet/app/Welcome_to_PolyNet.py
Python API
The core stages can be called directly from any script or notebook:
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/:
- Configuration reference — every YAML section, including automatic HPO
- Descriptors — polymer descriptor fusion and the PolyMetriX integration
- Explainability — GNN masking & TML SHAP attribution, normalisation, averaged vs per-model display, and statistical model comparison
- Running the pipeline & outputs — CLI flags, predicting on external data, target scaling, and the output directory layout
- API reference — project structure and the public Python API
- GUI & architecture — the Streamlit application and the core-vs-GUI design
- Development — running the test suite and extending PolyNet
Team
- Eduardo Aguilar (Chemist, Data Scientist, Research Software Engineer)
- David Winkler (Professor, Cheminformatician)
- Grazziela Figueredo (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):
@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 (1.0.0: 10.5281/zenodo.23302985).
Changes between versions are listed in CHANGELOG.md.
Metadata
Release files for polynet 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| polynet-1.0.3.tar.gz | 1.3 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| polynet-1.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 2.7 MB
Release files / polynet-1.0.3.tar.gz
| Download URL | polynet-1.0.3.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0c1ecb6a89c86dec73e0651601fe1f753e243570afccf803fe27724b417293e6
|
|
BLAKE2b-256 checksum How to use checksums |
bb8dae92cd5bb07bc6729c920b43d82d901c4e2ecd237159e5de9aeeb675b0c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / polynet-1.0.3-py3-none-any.whl
| Download URL | polynet-1.0.3-py3-none-any.whl |
|---|---|
| Size | 1.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b89bca86577676a1d31a510a2fad39fe9cbce84d490ea3f9a163dd387ff179b7
|
|
BLAKE2b-256 checksum How to use checksums |
262710f3514ddc23ee92faf733f3b74ef56c5df6ab03a5f01d82e615422a397c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log