Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mols matrix to grid image #6080

Merged
merged 36 commits into from
Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1dd046c
Start creating test for _MolsMatrixToLinear
bertiewooster Jan 14, 2023
2b5be83
Progress on _MolsMatrixToLinear
bertiewooster Jan 14, 2023
769a414
Passing _MolsMatrixToLinear tests:
bertiewooster Jan 14, 2023
930a25f
Raise exception if legends_matrix not same dimensions as mols_matrix
bertiewooster Jan 15, 2023
9578d75
Raise exception if highlight matrices not same dimensions as mols_matrix
bertiewooster Jan 15, 2023
4878126
Fix comment
bertiewooster Jan 15, 2023
85d338d
Rename to _MolsNestedToLinear
bertiewooster Jan 15, 2023
a77bb76
Check that each item in nested lists is a list
bertiewooster Jan 15, 2023
939ff89
Moved _MolsNestedToLinear to __init__.py
bertiewooster Feb 10, 2023
b20a73c
Attempt to revert to master to undo black autoformatting
bertiewooster Feb 11, 2023
3c19ca6
Revert to master; tests pass
bertiewooster Feb 11, 2023
0d060f7
Restored _MolsNestedToLinear and testMolsMatrixToLinear
bertiewooster Feb 11, 2023
d89819c
Removed obvious black formatting from my code
bertiewooster Feb 11, 2023
3ab7c9c
Removed black formatting from my __init__ code
bertiewooster Feb 11, 2023
a909fe3
Add some exception testing
bertiewooster Feb 11, 2023
64a3bcc
Add exception testing: other matrices aren't same length, or same row…
bertiewooster Feb 12, 2023
d012f42
Parametrize _nestedOrder test
bertiewooster Feb 12, 2023
76fab2f
Create one test for MolsMatrixToGridImage
bertiewooster Feb 12, 2023
94ba016
Test that all combinations of MolsMatrixToGridImage do not give an error
bertiewooster Feb 13, 2023
8e02e10
Replace list[list] type hint with just list to avoid error
bertiewooster Feb 13, 2023
3d57147
Add comment: Only test three matrices if supplied
bertiewooster May 24, 2023
f2511ad
Remove commented-out line
bertiewooster May 25, 2023
7afc10d
MolsMatrixToGridImage produces correct drawings
bertiewooster May 28, 2023
6f72611
Complete the docstrings
bertiewooster May 29, 2023
2036967
Improved MolsMatrixToGridImage docstring
bertiewooster May 30, 2023
14a0a39
Make column spacings consistent in text version of molgrid
bertiewooster Jun 7, 2023
7274a5e
Undo Black autoformatting
bertiewooster Jun 7, 2023
29a04d2
Remove some spacing. Clarify and move a comment.
bertiewooster Jun 7, 2023
321e0a8
Change variable names from first_second to firstSecond
bertiewooster Jun 7, 2023
d78ddc6
Remove extended docstring for _MolsNestedToLinear. Remove longestRow().
bertiewooster Jun 7, 2023
e17bb74
Correct drawing output types. Generalize check: instead of nested lis…
bertiewooster Jun 7, 2023
5cbb8a7
Merge branch 'master' into MolsMatrixToGridImage
bertiewooster Jun 8, 2023
12b7a03
Fix import formatting. Remove remaining underscores in middle of vari…
bertiewooster Jun 8, 2023
379bb21
Removed CheckElementsAreLists and calls to
bertiewooster Jun 8, 2023
4b5c334
Move helper fns to global namespace and prefix with _. Change expecte…
bertiewooster Jun 8, 2023
40f148e
Fix docstring example having returnPNG=True to note it returns a bina…
bertiewooster Jun 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 163 additions & 5 deletions rdkit/Chem/Draw/UnitTestDraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@
# which is included in the file license.txt, found at the root
# of the RDKit source tree.
#
import re
import os
import pathlib
import re
import sys
import tempfile
import unittest

from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit.Chem import Draw
from rdkit.Chem import rdDepictor
from rdkit.Chem import rdMolDescriptors
from rdkit.Chem import AllChem, Draw, rdDepictor, rdMolDescriptors
bertiewooster marked this conversation as resolved.
Show resolved Hide resolved

try:
from rdkit.Chem.Draw import IPythonConsole
Expand Down Expand Up @@ -50,6 +47,51 @@ def setUp(self):
IPythonConsole.UninstallIPythonRenderer()
self.mol = Chem.MolFromSmiles('c1c(C[15NH3+])ccnc1[C@](Cl)(Br)[C@](Cl)(Br)F')

# For testMolsMatrixToLinear and testMolsMatrixToLinear (which test MolsMatrixToGridImage and its helper _MolsNestedToLinear)
s = "NC(C)C(=O)"
mol = Chem.MolFromSmiles(s)
natoms = mol.GetNumAtoms()
nbonds = mol.GetNumBonds()

# Set up matrix with oligomer count for the molecules
# Should produce this grid:
# NC(C)C(=O)
# NC(C)C(=O)NC(C)C(=O)
# NC(C)C(=O)NC(C)C(=O)NC(C)C(=O) NC(C)C(=O)NC(C)C(=O)NC(C)C(=O)NC(C)C(=O)
repeats = [[1], [0, 2], [3, 0, 4]]

# Create molecule if there are 1 or more oligomers;
# otherwise, use None for molecule because drawing is distorted if use Chem.MolFromSmiles("")
self.mols_matrix = [[Chem.MolFromSmiles(s * count) if count else None for count in row] for row in repeats]

self.legends_matrix = [[str(count) + " unit(s)" for count in row] for row in repeats]

def ith_item_list(nunits, items_per_unit, i=0):
return [((n * items_per_unit) + i) for n in range(nunits)]

self.highlightAtomLists_matrix = [[ith_item_list(count, natoms, 0) for count in row] for row in repeats]

# Another bond is created when molecule is oligomerized, so to keep the bond type consistent,
# make items per unit one more than the number of bonds
self.highlightBondLists_matrix = [[ith_item_list(count, nbonds + 1, 1) for count in row] for row in repeats]

# Parametrize tests: In addition to supplying mols_matrix, supply 0-3 other matrices
# col labels: legends_matrix, highlightAtomLists_matrix, highlightBondLists_matrix
# Zero other matrices: 1 parameter set
self.param_sets = [(None, None, None ),
bertiewooster marked this conversation as resolved.
Show resolved Hide resolved
# One other matrix: 3 parameter sets
(self.legends_matrix, None, None ),
(None, self.highlightAtomLists_matrix, None ),
(None, None, self.highlightBondLists_matrix),
# Two other matrices: 3 parameter sets
(self.legends_matrix, self.highlightAtomLists_matrix, None ),
(self.legends_matrix, None, self.highlightBondLists_matrix),
(None, self.highlightAtomLists_matrix, self.highlightBondLists_matrix),
# All three other matrices: 1 parameter set
(self.legends_matrix, self.highlightAtomLists_matrix, self.highlightBondLists_matrix),
]


def test_interactive(self):
# We avoid checking in the code with development flag set
self.assertFalse(self.showAllImages)
Expand Down Expand Up @@ -213,6 +255,122 @@ def testGridSVG(self):
useSVG=True, drawOptions=dopts)
self.assertIn("class='note'", svg)

def testMolsMatrixToLinear(self):
mols, molsPerRow, legends, highlightAtomLists, highlightBondLists = Draw._MolsNestedToLinear(
self.mols_matrix, self.legends_matrix, self.highlightAtomLists_matrix, self.highlightBondLists_matrix)

nrows = len(self.mols_matrix)

def _nestedOrder(self, mols_matrix, legends_matrix, highlightAtomLists_matrix, highlightBondLists_matrix):
for r, row in enumerate(mols_matrix):
for c, item in enumerate(row):
linear_index = (r * molsPerRow) + c
# Test that items in 2D list are in correct position in 1D list
self.assertTrue(mols[linear_index] == item)
# Test that 1D list items are not lists
self.assertFalse(isinstance(item, list))

# Other three matrices (legends; atom and bond highlighting) need not be supplied;
# only test each if it's supplied
if legends_matrix is not None:
for r, row in enumerate(legends_matrix):
for c, item in enumerate(row):
linear_index = (r * molsPerRow) + c
# Test that items in 2D list are in correct position in 1D list
self.assertTrue(legends[linear_index] == item)
# Test that 1D list items are not lists
self.assertFalse(isinstance(item, list))

if highlightAtomLists_matrix is not None:
for r, row in enumerate(highlightAtomLists_matrix):
for c, item in enumerate(row):
linear_index = (r * molsPerRow) + c
# Test that items in 2D list are in correct position in 1D list
self.assertTrue(highlightAtomLists[linear_index] == item)
# For highlight parameters, entries are lists, so check that sub-items are not lists
for subitem in item:
self.assertFalse(isinstance(subitem, list))

if highlightBondLists_matrix is not None:
for r, row in enumerate(highlightBondLists_matrix):
for c, item in enumerate(row):
linear_index = (r * molsPerRow) + c
# Test that items in 2D list are in correct position in 1D list
self.assertTrue(highlightBondLists[linear_index] == item)
# For highlight parameters, entries are lists, so check that sub-items are not lists
for subitem in item:
self.assertFalse(isinstance(subitem, list))

# Test that 1D list has the correct length
self.assertTrue(len(mols) == nrows * molsPerRow)

# Parametrize tests: In addition to supplying mols_matrix, supply 0-3 other matrices
for param_set in self.param_sets:
_nestedOrder(self, self.mols_matrix, *param_set)

## Test that exceptions are thrown appropriately

# Test that supplying a non-nested list raises a ValueError
# Set up non-nested lists = first sublist of nested lists
mols_not_nested = self.mols_matrix[0]
legends_not_nested = self.legends_matrix[0]
highlightAtomLists_not_nested = self.highlightAtomLists_matrix[0]
highlightBondLists_not_nested = self.highlightBondLists_matrix[0]

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_not_nested)

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, legends_matrix=legends_not_nested)

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightAtomLists_matrix=highlightAtomLists_not_nested)

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightBondLists_matrix=highlightBondLists_not_nested)

# Test that raises ValueError if other matrices aren't same size (# rows) as mols_matrix
with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, legends_matrix=self.legends_matrix[0:1])

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightAtomLists_matrix=self.highlightAtomLists_matrix[0:1])

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightBondLists_matrix=self.highlightBondLists_matrix[0:1])

# Test that raises ValueError if other matrices' rows aren't same length as mols_matrix's corresponding row
# Remove last element from first row of each other matrix
legends_matrix_short_row0 = [self.legends_matrix[0][0:-1]] + [self.legends_matrix[1:]]
highlightAtomLists_matrix_short_row0 = [self.highlightAtomLists_matrix[0][0:-1]] + [self.highlightAtomLists_matrix[1:]]
highlightBondLists_matrix_short_row0 = [self.highlightBondLists_matrix[0][0:-1]] + [self.highlightBondLists_matrix[1:]]

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, legends_matrix=legends_matrix_short_row0)

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightAtomLists_matrix=highlightAtomLists_matrix_short_row0)

with self.assertRaises(ValueError):
Draw._MolsNestedToLinear(mols_matrix=self.mols_matrix, highlightBondLists_matrix=highlightBondLists_matrix_short_row0)


def testMolsMatrixToGridImage(self):
# Tests are that running Draw.MolsMatrixToGridImage doesn't give an error
# Parametrize tests: In addition to supplying mols_matrix, supply 0-3 other matrices
subImgSize = (200, 200)

kwargs_value = Draw.rdMolDraw2D.MolDrawOptions()
kwargs_value.addAtomIndices = True

for (legends_matrix, highlightAtomLists_matrix, highlightBondLists_matrix) in self.param_sets:
bertiewooster marked this conversation as resolved.
Show resolved Hide resolved
for useSVG in (True, False):
for returnPNG in (True, False):
dwg_subImgSize_nokwargs = Draw.MolsMatrixToGridImage(self.mols_matrix, subImgSize, legends_matrix=legends_matrix, highlightAtomLists_matrix=highlightAtomLists_matrix, highlightBondLists_matrix=highlightBondLists_matrix, useSVG=useSVG, returnPNG=returnPNG)
dwg_subImgSize_kwargs = Draw.MolsMatrixToGridImage(self.mols_matrix, subImgSize, legends_matrix=legends_matrix, highlightAtomLists_matrix=highlightAtomLists_matrix, highlightBondLists_matrix=highlightBondLists_matrix, useSVG=useSVG, returnPNG=returnPNG, drawOptions=kwargs_value)
dwg_nosubImgSize_nokwargs = Draw.MolsMatrixToGridImage(self.mols_matrix, legends_matrix=legends_matrix, highlightAtomLists_matrix=highlightAtomLists_matrix, highlightBondLists_matrix=highlightBondLists_matrix, useSVG=useSVG, returnPNG=returnPNG)
dwg_nosubImgSize_kwargs = Draw.MolsMatrixToGridImage(self.mols_matrix, legends_matrix=legends_matrix, highlightAtomLists_matrix=highlightAtomLists_matrix, highlightBondLists_matrix=highlightBondLists_matrix, useSVG=useSVG, returnPNG=returnPNG, drawOptions=kwargs_value)

def testDrawMorgan(self):
m = Chem.MolFromSmiles('c1ccccc1CC1CC1')
bi = {}
Expand Down
Loading