MolMiner-graphs 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- molminer_graphs-0.0.1/PKG-INFO +58 -0
- molminer_graphs-0.0.1/README.md +28 -0
- molminer_graphs-0.0.1/mminer_graphs/.DS_Store +0 -0
- molminer_graphs-0.0.1/mminer_graphs/__init__.py +13 -0
- molminer_graphs-0.0.1/mminer_graphs/graph/__init__.py +10 -0
- molminer_graphs-0.0.1/mminer_graphs/graph/graph.py +277 -0
- molminer_graphs-0.0.1/mminer_graphs/graph/graph_cluster.py +450 -0
- molminer_graphs-0.0.1/mminer_graphs/graph/graph_structure.py +465 -0
- molminer_graphs-0.0.1/mminer_graphs/graph/graph_utils.py +220 -0
- molminer_graphs-0.0.1/mminer_graphs/hyperparams/__init__.py +7 -0
- molminer_graphs-0.0.1/mminer_graphs/hyperparams/mlx_opt.py +469 -0
- molminer_graphs-0.0.1/mminer_graphs/hyperparams/opt_plot.py +213 -0
- molminer_graphs-0.0.1/mminer_graphs/hyperparams/torch_opt.py +372 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/__init__.py +10 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/crossval.py +236 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/mlx_latent_space.py +427 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/mlx_modeling.py +2237 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/mlx_summary.py +149 -0
- molminer_graphs-0.0.1/mminer_graphs/mlx_models/mlx_utils.py +84 -0
- molminer_graphs-0.0.1/mminer_graphs/model/__init__.py +11 -0
- molminer_graphs-0.0.1/mminer_graphs/model/crossval.py +222 -0
- molminer_graphs-0.0.1/mminer_graphs/model/graph_modeling.py +2150 -0
- molminer_graphs-0.0.1/mminer_graphs/model/latent_space.py +438 -0
- molminer_graphs-0.0.1/mminer_graphs/model/model_utils.py +194 -0
- molminer_graphs-0.0.1/mminer_graphs/plot/__init__.py +9 -0
- molminer_graphs-0.0.1/mminer_graphs/plot/mlx_plot.py +750 -0
- molminer_graphs-0.0.1/mminer_graphs/plot/plot.py +828 -0
- molminer_graphs-0.0.1/mminer_graphs/utils/func_ring.csv +23 -0
- molminer_graphs-0.0.1/mminer_graphs/visualizer/__init__.py +7 -0
- molminer_graphs-0.0.1/mminer_graphs/visualizer/explainer.py +0 -0
- molminer_graphs-0.0.1/mminer_graphs/visualizer/graph_visualizer.py +267 -0
- molminer_graphs-0.0.1/pyproject.toml +58 -0
- molminer_graphs-0.0.1/pyproject.toml.orig +54 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: MolMiner-graphs
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: For Creaming Molecular Graph Models
|
|
5
|
+
Author: Tony Eight Lin
|
|
6
|
+
Author-email: Tony Eight Lin <tonyelin@tmu.edu.tw>
|
|
7
|
+
License: Apache-2.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: matplotlib>=3.10.3
|
|
14
|
+
Requires-Dist: numpy>=2.0
|
|
15
|
+
Requires-Dist: pandas>=2.1
|
|
16
|
+
Requires-Dist: rdkit>=2023.9.5
|
|
17
|
+
Requires-Dist: seaborn>=0.12.2
|
|
18
|
+
Requires-Dist: scikit-learn>=1.6.1
|
|
19
|
+
Requires-Dist: torch>=2.1.0
|
|
20
|
+
Requires-Dist: torchinfo>=1.8.0
|
|
21
|
+
Requires-Dist: torch-geometric>=2.6.1
|
|
22
|
+
Requires-Dist: torchviz>=0.0.3
|
|
23
|
+
Requires-Dist: tabulate>=0.9.0
|
|
24
|
+
Requires-Dist: optuna>=4.9.0
|
|
25
|
+
Requires-Dist: mlx>=0.31.1 ; extra == 'mlx'
|
|
26
|
+
Requires-Dist: mlx-graphs>=0.0.9 ; extra == 'mlx'
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Provides-Extra: mlx
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# MolMiner - Graphs
|
|
32
|
+
[]()
|
|
33
|
+
[](https://pypi.org/project/mlx-mol-cluster/)
|
|
34
|
+
[](https://pytorch.org)
|
|
35
|
+
[](https://github.com/ml-explore/mlx)
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
This repo is a companion to the MolMiner project. It is focused on building deep learning molecular graph models built
|
|
39
|
+
using PyTorch or MLX.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
Installation of MolMiner-graphs is done as follows:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install MolMiner-graphs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
By default, this will only install the PyTorch backend. For users interested in MLX, this requires workstations using
|
|
50
|
+
Apple Silicon and can be installed as follows:
|
|
51
|
+
```bash
|
|
52
|
+
pip install "MolMiner-graphs[mlx]"
|
|
53
|
+
```
|
|
54
|
+
This will install both PyTorch and MLX on the Apple Silicon workstation.
|
|
55
|
+
|
|
56
|
+
## Tutorials
|
|
57
|
+
|
|
58
|
+
Tutorials and examples of how to use MolMiner-Graphs can be seen at the [Tutorials](tutorials/) directory.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# MolMiner - Graphs
|
|
2
|
+
[]()
|
|
3
|
+
[](https://pypi.org/project/mlx-mol-cluster/)
|
|
4
|
+
[](https://pytorch.org)
|
|
5
|
+
[](https://github.com/ml-explore/mlx)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
This repo is a companion to the MolMiner project. It is focused on building deep learning molecular graph models built
|
|
9
|
+
using PyTorch or MLX.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Installation of MolMiner-graphs is done as follows:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install MolMiner-graphs
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
By default, this will only install the PyTorch backend. For users interested in MLX, this requires workstations using
|
|
20
|
+
Apple Silicon and can be installed as follows:
|
|
21
|
+
```bash
|
|
22
|
+
pip install "MolMiner-graphs[mlx]"
|
|
23
|
+
```
|
|
24
|
+
This will install both PyTorch and MLX on the Apple Silicon workstation.
|
|
25
|
+
|
|
26
|
+
## Tutorials
|
|
27
|
+
|
|
28
|
+
Tutorials and examples of how to use MolMiner-Graphs can be seen at the [Tutorials](tutorials/) directory.
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Initialize submodules
|
|
3
|
+
"""
|
|
4
|
+
from .graph import AtomGraph, GLOBAL_VALUES
|
|
5
|
+
from .graph.graph_structure import PharmacophoreGraph, FunctionalGraph
|
|
6
|
+
from .graph.graph_cluster import JunctionTreeGraph, ClusterGraph
|
|
7
|
+
from .visualizer.graph_visualizer import Graph
|
|
8
|
+
from .model.graph_modeling import MolToGraph, Base, GCNNet, GINNet, GINENet, GSAGENet, GATNet, EarlyStopping
|
|
9
|
+
from .model.crossval import CrossVal
|
|
10
|
+
from .plot import Plots
|
|
11
|
+
|
|
12
|
+
__all__ = ["AtomGraph", "GLOBAL_VALUES", "PharmacophoreGraph", "FunctionalGraph", "JunctionTreeGraph", "ClusterGraph",
|
|
13
|
+
"Graph", "MolToGraph", "Plots"]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Initialize classes for graph features
|
|
3
|
+
"""
|
|
4
|
+
from .graph import MolGraph, AtomGraph, GLOBAL_VALUES
|
|
5
|
+
from .graph_cluster import JunctionTreeGraph, ClusterGraph
|
|
6
|
+
from .graph_structure import PharmacophoreGraph, FunctionalGraph
|
|
7
|
+
from .graph_utils import *
|
|
8
|
+
|
|
9
|
+
__all__ = ["MolGraph", "AtomGraph", "JunctionTreeGraph", "ClusterGraph", "PharmacophoreGraph", "FunctionalGraph",
|
|
10
|
+
"GLOBAL_VALUES"]
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Convert molecules into graph
|
|
3
|
+
Adapted from MMGX (https://github.com/ohuelab/MMGX.git)
|
|
4
|
+
Paper: "Enhancing property and activity prediction and interpretation using multiple molecular graph representations with MMGX"
|
|
5
|
+
Communications Chemistry (2024), https://doi.org/10.1038/s42004-024-01084-4
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from mminer_graphs.graph.graph_utils import *
|
|
9
|
+
from rdkit.Chem import rdchem
|
|
10
|
+
from rdkit import Chem
|
|
11
|
+
|
|
12
|
+
__all__ = ["MolGraph", "AtomGraph", "GLOBAL_VALUES"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# print global definition
|
|
16
|
+
def GLOBAL_VALUES():
|
|
17
|
+
# atom features
|
|
18
|
+
# print('ATOM Features:', ATOM_NUM) #todo add additional charges into list
|
|
19
|
+
print('ATOM Features: 142')
|
|
20
|
+
for (x, item) in enumerate(ATOMS):
|
|
21
|
+
print(f" {x}: {item}")
|
|
22
|
+
# degree
|
|
23
|
+
print(f" Atom Degree: 11")
|
|
24
|
+
print(f" Atom Valence: 7")
|
|
25
|
+
print(f" Formal charge: 5")
|
|
26
|
+
print(f" Hybridization: 6")
|
|
27
|
+
print(f" Aromaticity: 1")
|
|
28
|
+
print(f" Number of Hydrogens: 5")
|
|
29
|
+
print(f" Chirality: 5")
|
|
30
|
+
print(f" Ring status: 1")
|
|
31
|
+
print(f" Mass: 1")
|
|
32
|
+
|
|
33
|
+
# bond features
|
|
34
|
+
print('BOND Features:', BOND_NUM)
|
|
35
|
+
print(' Bond types:')
|
|
36
|
+
for (x, item) in enumerate(BONDS):
|
|
37
|
+
print(f' {x}: {item}')
|
|
38
|
+
|
|
39
|
+
print(' Bond flags:')
|
|
40
|
+
for (x, item) in enumerate(BOND_FEATURES):
|
|
41
|
+
print(f' {x + len(BONDS)}: {item}')
|
|
42
|
+
|
|
43
|
+
print(' Bond stereo:')
|
|
44
|
+
for (x, item) in enumerate(BOND_STEREO):
|
|
45
|
+
print(f' {x + len(BONDS) + len(BOND_FEATURES)}: {item}')
|
|
46
|
+
|
|
47
|
+
print(f' {len(BONDS) + len(BOND_FEATURES) + len(BOND_STEREO)}: stereo_atoms_present')
|
|
48
|
+
|
|
49
|
+
# features for functional graph
|
|
50
|
+
print('FUNCTIONAL Graph Features:', FUNCTIONAL_NUM)
|
|
51
|
+
for x in range(fparams.GetNumFuncGroups()):
|
|
52
|
+
if x == 27:
|
|
53
|
+
print('SWAP WITH 29')
|
|
54
|
+
if x == 29:
|
|
55
|
+
print('SWAP WITH 27')
|
|
56
|
+
print(f"{x}: {fparams.GetFuncGroup(x).GetProp('_Name')} {Chem.MolToSmarts(fparams.GetFuncGroup(x))}")
|
|
57
|
+
# functional graph bond features
|
|
58
|
+
print('FUNC_BOND Graph Bond Features', FUNCBOND_NUM)
|
|
59
|
+
for (x, item) in enumerate(FUNCBOND):
|
|
60
|
+
print(f"{x}: {item}")
|
|
61
|
+
|
|
62
|
+
print('FUNC_RING Functional Graph Rings', FUNCRING_NUM)
|
|
63
|
+
print(func_ring)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class MolGraph:
|
|
67
|
+
def __init__(self, smi=None, with_atom_index=True):
|
|
68
|
+
self.smi = mol_to_smiles(smiles_to_mol(smi, with_atom_index=with_atom_index)) # standardize smi
|
|
69
|
+
self.mol = smiles_to_mol(self.smi)
|
|
70
|
+
self.cliques = None
|
|
71
|
+
self.edges = None
|
|
72
|
+
self.graph_size = 0
|
|
73
|
+
self.node_index = []
|
|
74
|
+
self.node_features = []
|
|
75
|
+
self.edge_index = []
|
|
76
|
+
self.edge_features = []
|
|
77
|
+
|
|
78
|
+
def getMoleculeGraph(self):
|
|
79
|
+
return self.mol, self.smi, self.cliques, self.edges, self.graph_size, \
|
|
80
|
+
self.node_index, self.node_features, self.edge_index, self.edge_features,
|
|
81
|
+
|
|
82
|
+
def __str__(self):
|
|
83
|
+
if not isinstance(self, AtomGraph):
|
|
84
|
+
return "Molecule Graph: " + self.smi + "\n" + \
|
|
85
|
+
"Node Index:" + str(self.node_index) + "\n" + \
|
|
86
|
+
"Edge Index:" + str(self.edge_index) + "\n" + \
|
|
87
|
+
"Cliques:" + str(self.cliques)
|
|
88
|
+
else:
|
|
89
|
+
return "Molecule Graph: " + self.smi + "\n" + \
|
|
90
|
+
"Node Index:" + str(self.node_index) + "\n" + \
|
|
91
|
+
"Edge Index:" + str(self.edge_index)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ATOM-based
|
|
95
|
+
class AtomGraph(MolGraph):
|
|
96
|
+
def __init__(self, smi, normalize=True, with_atom_index=True):
|
|
97
|
+
super().__init__(smi)
|
|
98
|
+
self.smi = mol_to_smiles(smiles_to_mol(smi, with_atom_index=with_atom_index))
|
|
99
|
+
self.mol = smiles_to_mol(self.smi)
|
|
100
|
+
self.normalize = normalize
|
|
101
|
+
graph_size, node_index, node_attr, edge_index, edge_attr = self.mol_to_atom_graph(self.mol, normalize)
|
|
102
|
+
self.graph_size = graph_size
|
|
103
|
+
self.node_index = node_index
|
|
104
|
+
self.node_features = node_attr
|
|
105
|
+
self.edge_index = edge_index
|
|
106
|
+
self.edge_features = edge_attr
|
|
107
|
+
# atom graph only
|
|
108
|
+
self.cliques = [[x] for x in node_index]
|
|
109
|
+
self.edges = edge_index
|
|
110
|
+
|
|
111
|
+
def mol_to_atom_graph(self, mol=None, normalize=True):
|
|
112
|
+
"""
|
|
113
|
+
Convert molecules into graph embeddings. Will run default graph featurization in this order - graph_size,
|
|
114
|
+
node_index, node_attr, edge_index, edge_attr.
|
|
115
|
+
:param mol: Chem.rdchem.Mol
|
|
116
|
+
A molecule rendered in RDKit for graph featurization.
|
|
117
|
+
:param normalize: bool
|
|
118
|
+
Convert vector into a distibution where values add up to 1.
|
|
119
|
+
:return:
|
|
120
|
+
"""
|
|
121
|
+
if mol is None:
|
|
122
|
+
mol = self.mol
|
|
123
|
+
|
|
124
|
+
graph_size = mol.GetNumAtoms()
|
|
125
|
+
|
|
126
|
+
node_attr = []
|
|
127
|
+
node_index = []
|
|
128
|
+
for atom in mol.GetAtoms():
|
|
129
|
+
# print(atom.GetAtomicNum())
|
|
130
|
+
node_feature = self._get_atom_feats(atom, chirality=True)
|
|
131
|
+
node_attr.append(list(node_feature))
|
|
132
|
+
node_index.append(atom.GetIdx())
|
|
133
|
+
|
|
134
|
+
edge_attr = []
|
|
135
|
+
edge_index = []
|
|
136
|
+
# bidirectional edges
|
|
137
|
+
for bond in mol.GetBonds():
|
|
138
|
+
edge_feature = self._get_bond_feats(bond)
|
|
139
|
+
# from A -> B
|
|
140
|
+
edge_attr.append(list(edge_feature))
|
|
141
|
+
edge_index.append((bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()))
|
|
142
|
+
|
|
143
|
+
# from B -> A
|
|
144
|
+
edge_attr.append(list(edge_feature))
|
|
145
|
+
edge_index.append((bond.GetEndAtomIdx(), bond.GetBeginAtomIdx()))
|
|
146
|
+
|
|
147
|
+
return graph_size, node_index, node_attr, edge_index, edge_attr
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def _get_atom_feats(atom, chirality: bool = True):
|
|
151
|
+
"""
|
|
152
|
+
Get atom features (Total: 142). The features are ordered as follows:
|
|
153
|
+
- atomic number (100)
|
|
154
|
+
- degree (11)
|
|
155
|
+
- implicit valence (7)
|
|
156
|
+
- formal charge (5)
|
|
157
|
+
- hybridization (6)
|
|
158
|
+
- aromaticity (1)
|
|
159
|
+
- number of hydrogens (5)
|
|
160
|
+
- chirality (5)
|
|
161
|
+
- ring status (1)
|
|
162
|
+
- mass (1)
|
|
163
|
+
"""
|
|
164
|
+
atom_feats = []
|
|
165
|
+
|
|
166
|
+
# atomic number
|
|
167
|
+
atom_feats += one_hot_encode(atom.GetAtomicNum(), ATOMIC_NUM)
|
|
168
|
+
|
|
169
|
+
# atom degree (number of directly bonded atoms)
|
|
170
|
+
atom_feats += one_hot_encode(atom.GetDegree(), list(range(11)))
|
|
171
|
+
|
|
172
|
+
# implicit valence
|
|
173
|
+
atom_feats += one_hot_encode(atom.GetValence(Chem.ValenceType.IMPLICIT), list(range(7)))
|
|
174
|
+
|
|
175
|
+
# formal charge
|
|
176
|
+
formal_charges = [-2, -1, 0, 1, 2]
|
|
177
|
+
atom_feats += one_hot_encode(atom.GetFormalCharge(), formal_charges)
|
|
178
|
+
|
|
179
|
+
# hybridization
|
|
180
|
+
hybridizations = [
|
|
181
|
+
Chem.rdchem.HybridizationType.SP,
|
|
182
|
+
Chem.rdchem.HybridizationType.SP2,
|
|
183
|
+
Chem.rdchem.HybridizationType.SP3,
|
|
184
|
+
Chem.rdchem.HybridizationType.SP3D,
|
|
185
|
+
Chem.rdchem.HybridizationType.SP3D2,
|
|
186
|
+
'Unknown'
|
|
187
|
+
]
|
|
188
|
+
atom_feats += one_hot_encode(atom.GetHybridization(), hybridizations)
|
|
189
|
+
|
|
190
|
+
# aromatic
|
|
191
|
+
atom_feats += [int(atom.GetIsAromatic())]
|
|
192
|
+
|
|
193
|
+
# number of Hs
|
|
194
|
+
atom_feats += one_hot_encode(atom.GetTotalNumHs(), list(range(5)))
|
|
195
|
+
|
|
196
|
+
# chirality
|
|
197
|
+
if chirality:
|
|
198
|
+
try:
|
|
199
|
+
chiral_tags = [
|
|
200
|
+
rdchem.ChiralType.CHI_UNSPECIFIED,
|
|
201
|
+
rdchem.ChiralType.CHI_TETRAHEDRAL_CW,
|
|
202
|
+
rdchem.ChiralType.CHI_TETRAHEDRAL_CCW,
|
|
203
|
+
rdchem.ChiralType.CHI_OTHER
|
|
204
|
+
]
|
|
205
|
+
atom_feats += one_hot_encode(atom.GetChiralTag(), chiral_tags)
|
|
206
|
+
except:
|
|
207
|
+
atom_feats += [0, 0]
|
|
208
|
+
atom_feats += [int(atom.HasProp('_ChiralityPossible'))]
|
|
209
|
+
|
|
210
|
+
# check if atom is in ring
|
|
211
|
+
atom_feats += [np.multiply(atom.IsInRing(), 1)]
|
|
212
|
+
|
|
213
|
+
# atom mass
|
|
214
|
+
atom_feats += [atom.GetMass() / 100] # normalize atomic mass between 0 and 1
|
|
215
|
+
|
|
216
|
+
return np.array(atom_feats, dtype=np.float32)
|
|
217
|
+
|
|
218
|
+
@staticmethod
|
|
219
|
+
def _get_bond_feats(bond, chirality: bool = True):
|
|
220
|
+
"""
|
|
221
|
+
Get bond features (Total: 11). The features are ordered as follows:
|
|
222
|
+
- numm bond (1)
|
|
223
|
+
- bond type (4)
|
|
224
|
+
- conjugated (1)
|
|
225
|
+
- aromatic (1)
|
|
226
|
+
- ring (1)
|
|
227
|
+
- stereo info (7)
|
|
228
|
+
- stereo atom present (1)
|
|
229
|
+
"""
|
|
230
|
+
# bond features
|
|
231
|
+
bond_feats = []
|
|
232
|
+
|
|
233
|
+
# null bond
|
|
234
|
+
bond_feats += [int(bond is None)]
|
|
235
|
+
if bond is None:
|
|
236
|
+
return np.zeros(16, dtype=np.float32)
|
|
237
|
+
|
|
238
|
+
# bond info
|
|
239
|
+
bond_type = [
|
|
240
|
+
Chem.rdchem.BondType.SINGLE,
|
|
241
|
+
Chem.rdchem.BondType.DOUBLE,
|
|
242
|
+
Chem.rdchem.BondType.TRIPLE,
|
|
243
|
+
Chem.rdchem.BondType.AROMATIC,
|
|
244
|
+
]
|
|
245
|
+
bond_feats += one_hot_encode(bond.GetBondType(), bond_type)
|
|
246
|
+
|
|
247
|
+
# bond conjugation and ring status
|
|
248
|
+
bond_feats += [int(bond.GetIsConjugated())]
|
|
249
|
+
bond_feats += [int(bond.GetIsAromatic())]
|
|
250
|
+
bond_feats += [int(bond.IsInRing())]
|
|
251
|
+
|
|
252
|
+
# stereo info
|
|
253
|
+
stereo_feats = [
|
|
254
|
+
Chem.rdchem.BondStereo.STEREONONE,
|
|
255
|
+
Chem.rdchem.BondStereo.STEREOANY,
|
|
256
|
+
Chem.rdchem.BondStereo.STEREOZ,
|
|
257
|
+
Chem.rdchem.BondStereo.STEREOE,
|
|
258
|
+
Chem.rdchem.BondStereo.STEREOCIS,
|
|
259
|
+
Chem.rdchem.BondStereo.STEREOTRANS,
|
|
260
|
+
'Unknown'
|
|
261
|
+
]
|
|
262
|
+
bond_feats += one_hot_encode(bond.GetStereo(), stereo_feats)
|
|
263
|
+
|
|
264
|
+
if chirality:
|
|
265
|
+
try:
|
|
266
|
+
stereo_atoms = bond.GetStereoAtoms()
|
|
267
|
+
bond_feats.append(len(stereo_atoms) > 0)
|
|
268
|
+
except Exception:
|
|
269
|
+
bond_feats.append(False)
|
|
270
|
+
|
|
271
|
+
return np.array(bond_feats, dtype=np.float32)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
if __name__ == "__main__":
|
|
275
|
+
import doctest
|
|
276
|
+
|
|
277
|
+
doctest.testmod()
|