A simple and reliable Python wrapper for calculating PaDEL molecular descriptors and fingerprints. This library takes care of installing a matching Java runtime, dispatching molecules to the bundled PaDEL executable, and collecting the results into a tidy pandas DataFrame β so you can stay in RDKit/pandas-land.
- 𧬠1875 descriptors & 12 fingerprint types β 1444 1D/2D and 431 3D descriptors, plus FP, ExtFP, EStateFP, GraphFP, MACCSFP, PubchemFP, SubFP(C), KRFP(C) and AP2DFP(C) fingerprints, straight from PaDEL-Descriptor.
- β Zero Java setup β automatically downloads, caches and reuses a matching JRE on first use; nothing to install by hand.
- β‘ Parallel by design β spread the work across multiple CPU cores with configurable
njobs/chunksize, each worker running its own single-core-pinned JVM. - π‘οΈ Hang-proof β some 3D descriptors (e.g. WHIM) can fail to converge on degenerate geometries; an optional per-descriptor
timeoutguarantees you getNaNback instead of a frozen process. - π§― Never silently misaligned β molecules that fail, get skipped, or lack hydrogens/conformers are handled explicitly and reported, never dropped without a trace.
- π pandas-native output β results come back as a ready-to-use
DataFrame, one row per molecule. - π Rich metadata β inspect each descriptor's description, sub-components and 3D requirement programmatically.
- π§© Configurable fingerprints β tune bit size and search depth for the fingerprints that support it.
Olivier J. M. BΓ©quignon is neither the copyright holder of PaDEL nor responsible for it. The work carried out here concerns:
- the Python wrapper,
- the ePaDEL executable,
- the extendedlibpadeldescriptor library.
If you use this wrapper in your research, please cite the original PaDEL publication in addition to this software package:
-
Original PaDEL paper:
Yap, C.W. (2011), PaDEL-descriptor: An open source software to calculate molecular descriptors and fingerprints. Journal of Computational Chemistry, 32(7), 1466β1474. DOI: 10.1002/jcc.21707
-
This wrapper:
Please refer to the repository at github.com/OlivierBeq/PaDEL_pywrapper for citation details.
pip install padel-pywrapperOr from source:
git clone https://github.com/OlivierBeq/PaDEL_pywrapper.git
pip install ./PaDEL_pywrapper- Python 3.11+
- RDKit
Descriptors of the module PaDEL_pywrapper.descriptor can be computed as follows:
With pip:
from PaDEL_pywrapper import PaDEL
from PaDEL_pywrapper.descriptor import ALOGP, Crippen, FMF
from rdkit import Chem
smiles_list = [
# erlotinib
"n1cnc(c2cc(c(cc12)OCCOC)OCCOC)Nc1cc(ccc1)C#C",
# midecamycin
"CCC(=O)O[C@@H]1CC(=O)O[C@@H](C/C=C/C=C/[C@@H]([C@@H](C[C@@H]([C@@H]([C@H]1OC)O[C@H]2[C@@H]([C@H]([C@@H]([C@H](O2)C)O[C@H]3C[C@@]([C@H]([C@@H](O3)C)OC(=O)CC)(C)O)N(C)C)O)CC=O)C)O)C",
# selenofolate
"C1=CC(=CC=C1C(=O)NC(CCC(=O)OCC[Se]C#N)C(=O)O)NCC2=CN=C3C(=N2)C(=O)NC(=N3)N",
]
mols = [Chem.MolFromSmiles(smiles) for smiles in smiles_list]
descriptors = [ALOGP, Crippen, FMF]
padel = PaDEL(descriptors)
print(padel.calculate(mols))Instances of descriptors can be supplied as well:
descriptors = [ALOGP(), Crippen(), FMF()]
padel = PaDEL(descriptors)
print(padel.calculate(mols))To calculate all possible descriptors, import the descriptors list from the PaDEL_pywrapper module directly:
from PaDEL_pywrapper import descriptors
padel = PaDEL(descriptors)
print(padel.calculate(mols))By default, the ignore_3D parameter is set to True, preventing any provided 3D descriptor from being calculated.
Should molecules with 3D coordinates be provided, one can turn on 3D descriptor calculation:
from rdkit.Chem import AllChem
from PaDEL_pywrapper.descriptor import WHIM
mols = [Chem.AddHs(mol) for mol in mols]
_ = [AllChem.EmbedMolecule(mol) for mol in mols]
descriptors_3d = [ALOGP, Crippen, FMF, WHIM]
padel = PaDEL(descriptors_3d, ignore_3D=False)
print(padel.calculate(mols))
β οΈ A warning is raised if molecules lack hydrogens.β οΈ An exception is raised if molecules do not have 3D coordinates β but only when a 3D descriptor (likeWHIMabove) is actually requested; a purely 2D descriptor list computes 2D coordinates on the fly instead.
mol = Chem.MolFromSmiles('CCC')
padel = PaDEL(descriptors_3d, ignore_3D=False)
print(padel.calculate([mol]))
# ValueError: Cannot calculate descriptors for a conformer-less moleculeSome 3D descriptors (e.g. WHIM) rely on an eigenvalue decomposition that can fail to converge β and hang indefinitely β for molecules with degenerate 3D geometry (very few heavy atoms, near-linear/near-planar arrangements). π‘οΈ Pass a timeout (in seconds) to guarantee that any descriptor exceeding it returns NaN for that molecule instead of blocking the whole batch:
padel = PaDEL(descriptors_3d, ignore_3D=False)
print(padel.calculate(mols, timeout=20))Fingerprints of the module PaDEL_pywrapper.descriptor can be computed as follows:
from PaDEL_pywrapper.descriptor import GraphOnlyFP
fp = GraphOnlyFP
padel = PaDEL([fp], ignore_3D=False)
print(padel.calculate(mols))Custom parameter sets can be provided for some fingerprints:
fp = GraphOnlyFP(size=2048, searchDepth=8)
padel = PaDEL([fp], ignore_3D=False)
print(padel.calculate(mols))Speed things up by spreading molecules across several CPU cores. Each worker runs its own single-core-pinned JVM, so parallelism comes purely from the number of processes spawned β not from oversubscribing the host:
padel = PaDEL(descriptors)
print(padel.calculate(mols, njobs=8))By default, molecules are auto-balanced evenly across njobs workers (chunksize=None), which minimizes JVM startup overhead while keeping every worker busy β the fastest setting for most workloads. A fixed chunksize can be provided instead if finer control is needed.
Details about each descriptor and fingerprint can be obtained as follows:
print(ALOGP.description)
print(GraphOnlyFP.description)For full details about all descriptors, one can obtain the path to the original Excel file of the PaDEL descriptors with:
print(padel.details)This project is licensed under the MIT License - see the LICENSE file for details.
def calculate(mols, show_banner=True, njobs=1, chunksize=None, timeout=None):Calculates PaDEL molecular descriptors and/or fingerprints. Installs a matching JRE on first use if none is found.
- mols : Iterable[Chem.Mol] RDKit molecule objects for which to obtain PaDEL descriptors.
- show_banner : bool Displays default notice about PaDEL descriptors.
- njobs : int
Number of concurrent processes used to calculate descriptors in parallel; must not exceed the
number of available CPU cores. Each spawned Java process is pinned to a single core
(
-XX:ActiveProcessorCount=1), since parallelism comes from spawningnjobsOS processes rather than from letting each JVM oversubscribe the host's full core count. - chunksize : int | None
Number of molecules processed per worker process. If
None(default), molecules are auto-balanced across allnjobsworkers so every worker gets work. Ignored ifnjobsis 1. - timeout : float | None
Maximum number of seconds allowed for each descriptor/fingerprint calculation for a single
molecule.
None(default) waits indefinitely. Guards against 3D descriptors (e.g.WHIM) that can hang on degenerate geometries β the offending molecule getsNaNinstead of blocking the whole batch. - return_type : pd.DataFrame Pandas DataFrame containing PaDEL molecular descriptors and/or fingerprints, one row per molecule.
Descriptor(name, is_3D)Metadata holder for a single PaDEL descriptor family (e.g. ALOGP, WHIM). Instances are
pre-created and importable by name from PaDEL_pywrapper.descriptor.
- name : str Name of the descriptor as known to PaDEL.
- is_3D : bool Whether the descriptor requires 3D molecular coordinates.
- subcomponents : list[str] Names of the individual output columns making up this descriptor.
- description : pd.DataFrame Human-readable description of each sub-component.
Fingerprint(name)Metadata holder for a single PaDEL fingerprint type. Instances are pre-created and importable
by name from PaDEL_pywrapper.descriptor; configurable ones (FP, GraphOnlyFP) can be
called with size/searchDepth to override the defaults.
- name : str Name of the fingerprint as known to PaDEL.
- size : int | None Number of bits, if configurable for this fingerprint type.
- searchDepth : int | None Search depth, if configurable for this fingerprint type.