CoolFace
Apppublic

YuWang0103/LGGM-Text2Graph

sourceHugging Facemitupdated 2y agoView on Hugging Face
1likes
visualization.py222 linesDownload Raw Back to analysis
1import os2 3from rdkit import Chem4from rdkit.Chem import Draw, AllChem5from rdkit.Geometry import Point3D6from rdkit import RDLogger7import imageio8import networkx as nx9import numpy as np10import rdkit.Chem11import wandb12import matplotlib.pyplot as plt13 14 15 16 17 18class MolecularVisualization:19    def __init__(self, remove_h, dataset_infos):20        self.remove_h = remove_h21        self.dataset_infos = dataset_infos22 23    def mol_from_graphs(self, node_list, adjacency_matrix):24        """25        Convert graphs to rdkit molecules26        node_list: the nodes of a batch of nodes (bs x n)27        adjacency_matrix: the adjacency_matrix of the molecule (bs x n x n)28        """29        # dictionary to map integer value to the char of atom30        atom_decoder = self.dataset_infos.atom_decoder31 32        # create empty editable mol object33        mol = Chem.RWMol()34 35        # add atoms to mol and keep track of index36        node_to_idx = {}37        for i in range(len(node_list)):38            if node_list[i] == -1:39                continue40            a = Chem.Atom(atom_decoder[int(node_list[i])])41            molIdx = mol.AddAtom(a)42            node_to_idx[i] = molIdx43 44        for ix, row in enumerate(adjacency_matrix):45            for iy, bond in enumerate(row):46                # only traverse half the symmetric matrix47                if iy <= ix:48                    continue49                if bond == 1:50                    bond_type = Chem.rdchem.BondType.SINGLE51                elif bond == 2:52                    bond_type = Chem.rdchem.BondType.DOUBLE53                elif bond == 3:54                    bond_type = Chem.rdchem.BondType.TRIPLE55                elif bond == 4:56                    bond_type = Chem.rdchem.BondType.AROMATIC57                else:58                    continue59                mol.AddBond(node_to_idx[ix], node_to_idx[iy], bond_type)60 61        try:62            mol = mol.GetMol()63        except rdkit.Chem.KekulizeException:64            print("Can't kekulize molecule")65            mol = None66        return mol67 68    def visualize(self, path: str, molecules: list, num_molecules_to_visualize: int, log='graph'):69        # define path to save figures70        if not os.path.exists(path):71            os.makedirs(path)72 73        # visualize the final molecules74        print(f"Visualizing {num_molecules_to_visualize} of {len(molecules)}")75        if num_molecules_to_visualize > len(molecules):76            print(f"Shortening to {len(molecules)}")77            num_molecules_to_visualize = len(molecules)78        79        for i in range(num_molecules_to_visualize):80            file_path = os.path.join(path, 'molecule_{}.png'.format(i))81            mol = self.mol_from_graphs(molecules[i][0].numpy(), molecules[i][1].numpy())82            try:83                Draw.MolToFile(mol, file_path)84                if wandb.run and log is not None:85                    print(f"Saving {file_path} to wandb")86                    wandb.log({log: wandb.Image(file_path)}, commit=True)87            except rdkit.Chem.KekulizeException:88                print("Can't kekulize molecule")89 90 91    def visualize_chain(self, path, nodes_list, adjacency_matrix, trainer=None):92        RDLogger.DisableLog('rdApp.*')93        # convert graphs to the rdkit molecules94        mols = [self.mol_from_graphs(nodes_list[i], adjacency_matrix[i]) for i in range(nodes_list.shape[0])]95 96        # find the coordinates of atoms in the final molecule97        final_molecule = mols[-1]98        AllChem.Compute2DCoords(final_molecule)99 100        coords = []101        for i, atom in enumerate(final_molecule.GetAtoms()):102            positions = final_molecule.GetConformer().GetAtomPosition(i)103            coords.append((positions.x, positions.y, positions.z))104 105        # align all the molecules106        for i, mol in enumerate(mols):107            AllChem.Compute2DCoords(mol)108            conf = mol.GetConformer()109            for j, atom in enumerate(mol.GetAtoms()):110                x, y, z = coords[j]111                conf.SetAtomPosition(j, Point3D(x, y, z))112 113        # draw gif114        save_paths = []115        num_frams = nodes_list.shape[0]116 117        for frame in range(num_frams):118            file_name = os.path.join(path, 'fram_{}.png'.format(frame))119            Draw.MolToFile(mols[frame], file_name, size=(300, 300), legend=f"Frame {frame}")120            save_paths.append(file_name)121 122        imgs = [imageio.imread(fn) for fn in save_paths]123        gif_path = os.path.join(os.path.dirname(path), '{}.gif'.format(path.split('/')[-1]))124        imgs.extend([imgs[-1]] * 10)125        imageio.mimsave(gif_path, imgs, subrectangles=True, duration=20)126 127        if wandb.run:128            print(f"Saving {gif_path} to wandb")129            wandb.log({"chain": wandb.Video(gif_path, fps=5, format="gif")}, commit=True)130 131        # draw grid image132        try:133            img = Draw.MolsToGridImage(mols, molsPerRow=10, subImgSize=(200, 200))134            img.save(os.path.join(path, '{}_grid_image.png'.format(path.split('/')[-1])))135        except Chem.rdchem.KekulizeException:136            print("Can't kekulize molecule")137        return mols138 139 140class NonMolecularVisualization:141    def to_networkx(self, node_list, adjacency_matrix):142        """143        Convert graphs to networkx graphs144        node_list: the nodes of a batch of nodes (bs x n)145        adjacency_matrix: the adjacency_matrix of the molecule (bs x n x n)146        """147        graph = nx.Graph()148 149        for i in range(len(node_list)):150            if node_list[i] == -1:151                continue152            graph.add_node(i, number=i, symbol=node_list[i], color_val=node_list[i])153 154        rows, cols = np.where(adjacency_matrix >= 1)155        edges = zip(rows.tolist(), cols.tolist())156        for edge in edges:157            edge_type = adjacency_matrix[edge[0]][edge[1]]158            graph.add_edge(edge[0], edge[1], color=float(edge_type), weight=3 * edge_type)159 160        return graph161 162    def visualize_non_molecule(self, graph, pos, path, iterations=100, node_size=100, largest_component=False):163        if largest_component:164            CGs = [graph.subgraph(c) for c in nx.connected_components(graph)]165            CGs = sorted(CGs, key=lambda x: x.number_of_nodes(), reverse=True)166            graph = CGs[0]167 168        # Plot the graph structure with colors169        if pos is None:170            pos = nx.spring_layout(graph, iterations=iterations)171 172        # Set node colors based on the eigenvectors173        w, U = np.linalg.eigh(nx.normalized_laplacian_matrix(graph).toarray())174        vmin, vmax = np.min(U[:, 1]), np.max(U[:, 1])175        m = max(np.abs(vmin), vmax)176        vmin, vmax = -m, m177 178        plt.figure()179        nx.draw(graph, pos, font_size=5, node_size=node_size, with_labels=False, node_color=U[:, 1],180                cmap=plt.cm.coolwarm, vmin=vmin, vmax=vmax, edge_color='grey')181 182        plt.tight_layout()183        plt.savefig(path)184        plt.close("all")185 186    def visualize(self, path: str, graphs: list, num_graphs_to_visualize: int, log='graph'):187        # define path to save figures188        if not os.path.exists(path):189            os.makedirs(path)190 191        # visualize the final molecules192        for i in range(num_graphs_to_visualize):193            file_path = os.path.join(path, 'graph_{}.png'.format(i))194            graph = self.to_networkx(graphs[i][0].numpy(), graphs[i][1].numpy())195            self.visualize_non_molecule(graph=graph, pos=None, path=file_path)196            im = plt.imread(file_path)197            if wandb.run and log is not None:198                wandb.log({log: [wandb.Image(im, caption=file_path)]})199 200    def visualize_chain(self, path, nodes_list, adjacency_matrix):201        # convert graphs to networkx202        graphs = [self.to_networkx(nodes_list[i], adjacency_matrix[i]) for i in range(nodes_list.shape[0])]203        # find the coordinates of atoms in the final molecule204        final_graph = graphs[-1]205        final_pos = nx.spring_layout(final_graph, seed=0)206 207        # draw gif208        save_paths = []209        num_frams = nodes_list.shape[0]210 211        for frame in range(num_frams):212            file_name = os.path.join(path, 'fram_{}.png'.format(frame))213            self.visualize_non_molecule(graph=graphs[frame], pos=final_pos, path=file_name)214            save_paths.append(file_name)215 216        imgs = [imageio.imread(fn) for fn in save_paths]217        gif_path = os.path.join(os.path.dirname(path), '{}.gif'.format(path.split('/')[-1]))218        imgs.extend([imgs[-1]] * 10)219        imageio.mimsave(gif_path, imgs, subrectangles=True, duration=20)220        if wandb.run:221            wandb.log({'chain': [wandb.Video(gif_path, caption=gif_path, format="gif")]})222