def get_coord_nwchem(f): """ Extract XYZ coordinate from NWChem output file. Parameters ---------- f : str User input filename. Returns ------- atom : list Full atomic labels of complex. coord : ndarray Full atomic coordinates of complex. """ nwchem_file = open(f, "r") nline = nwchem_file.readlines() start = 0 end = 0 atom, coord = [], [] for i in range(len(nline)): if "Optimization converged" in nline[i]: start = i for i in range(len(nline)): if "No. of atoms" in nline[i]: end = int(nline[i].split()[4]) start = start + 18 end = start + end # The 1st line of coordinate is at 18 lines next to 'Optimization converged' for line in nline[start:end]: dat = line.split() dat1 = int(float(dat[2])) coord_x = float(dat[3]) coord_y = float(dat[4]) coord_z = float(dat[5]) dat1 = elements.check_atom(dat1) atom.append(dat1) coord.append([coord_x, coord_y, coord_z]) nwchem_file.close() coord = np.asarray(coord, dtype=np.float64) return atom, coord
def get_coord_gaussian(f): """ Extract XYZ coordinate from Gaussian output file. Parameters ---------- f : str User input filename. Returns ------- atom : list Full atomic labels of complex. coord : ndarray Full atomic coordinates of complex. """ gaussian_file = open(f, "r") nline = gaussian_file.readlines() start = 0 end = 0 atom, coord = [], [] for i in range(len(nline)): if "Standard orientation:" in nline[i]: start = i for i in range(start + 5, len(nline)): if "---" in nline[i]: end = i break for line in nline[start + 5:end]: data = line.split() data1 = int(data[1]) coord_x = float(data[3]) coord_y = float(data[4]) coord_z = float(data[5]) data1 = elements.check_atom(data1) atom.append(data1) coord.append([coord_x, coord_y, coord_z]) gaussian_file.close() coord = np.asarray(coord, dtype=np.float64) return atom, coord
def on_pick(event): """ Pick point and get XYZ data Parameters ---------- event : object Event object for on-pick function. Examples -------- >>> def on_pick(event): >>> ... ind = event.ind >>> ... print("on_pick scatter:", ind, np.take(x, ind), np.take(y, ind)) """ ind = event.ind[0] x, y, z = event.artist._offsets3d for i in range(len(self.atom)): if x[ind] == self.coord[i][0]: if y[ind] == self.coord[i][1]: if z[ind] == self.coord[i][2]: atom = self.atom[i] break results = f"{i + 1} {atom} : {x[ind]} {y[ind]} {z[ind]}" coord = [x[ind], y[ind], z[ind]] insert_text(results, coord, group) # Highlight selected atom index = elements.check_atom(atom) ax.scatter( x[ind], y[ind], z[ind], marker="o", linewidths=0.5, edgecolors="orange", picker=5, alpha=0.5, color="yellow", s=elements.check_radii(index) * 400, )
def octa_and_face(ao, co, save="not_save"): """ Display 3D structure of octahedral complex with 8 faces. Parameters ---------- ao : list Atomic labels of octahedral structure. co : list Atomic coordinates of octahedral structure. save : str Name of image file to save. If this argument is not set by user, do not save a figure as image. Returns ------- None : None """ fig = plt.figure() ax = Axes3D(fig) # Plot atoms for i in range(len(co)): # Determine atomic number n = elements.check_atom(ao[i]) ax.scatter(co[i][0], co[i][1], co[i][2], marker='o', linewidths=0.5, edgecolors='black', color=elements.check_color(n), label=f"{ao[i]}", s=elements.check_radii(n) * 300) # Draw 8 faces # Get atomic coordinates of octahedron _, c_ref, _, _ = tools.find_faces_octa(co) # Create array of vertices for 8 faces vertices_list = [] for i in range(8): get_vertices = c_ref[i].tolist() x, y, z = zip(*get_vertices) vertices = [list(zip(x, y, z))] vertices_list.append(vertices) # Added faces color_list = [ "red", "blue", "green", "yellow", "violet", "cyan", "brown", "grey" ] for i in range(len(vertices_list)): ax.add_collection3d( Poly3DCollection(vertices_list[i], alpha=0.5, color=color_list[i])) # Draw line for i in range(1, len(co)): merge = list(zip(co[0], co[i])) x, y, z = merge ax.plot(x, y, z, 'k-', color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = plt.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r'X', fontsize=15) ax.set_ylabel(r'Y', fontsize=15) ax.set_zlabel(r'Z', fontsize=15) ax.set_title('Octahedral structure with faces', fontsize="12") ax.grid(True) # plt.axis('equal') if save != "not_save": plt.savefig('{0}.png'.format(save)) plt.show()
def all_atom(fal, fcl, save="not_save"): """ Display 3D structure of octahedral complex with label for each atoms. Parameters ---------- fal : list Atomic labels of full complex. fcl : list Atomic coordinates of full complex. save : str Name of image file to save. If this argument is not set by user, do not save a figure as image. Returns ------- None : None """ fig = plt.figure() ax = Axes3D(fig) # ax = fig.add_subplot(111, projection='3d') # Plot all atoms for i in range(len(fcl)): # Determine atomic number n = elements.check_atom(fal[i]) ax.scatter(fcl[i][0], fcl[i][1], fcl[i][2], marker='o', linewidths=0.5, edgecolors='black', color=elements.check_color(n), label=f"{fal[i]}", s=elements.check_radii(n) * 300) # Calculate distance bond_list = tools.find_bonds(fal, fcl) atoms_pair = [] for i in range(len(bond_list)): get_atoms = bond_list[i] x, y, z = zip(*get_atoms) atoms = list(zip(x, y, z)) atoms_pair.append(atoms) # Draw line for i in range(len(atoms_pair)): merge = list(zip(atoms_pair[i][0], atoms_pair[i][1])) x, y, z = merge ax.plot(x, y, z, 'k-', color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = plt.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r'X', fontsize=15) ax.set_ylabel(r'Y', fontsize=15) ax.set_zlabel(r'Z', fontsize=15) ax.set_title('Full complex', fontsize="12") ax.grid(True) # plt.axis('equal') if save != "not_save": plt.savefig('{0}.png'.format(save)) plt.show()
def octa(ao, co, save="not_save"): """ Display 3D structure of octahedral complex. Parameters ---------- ao : list Atomic labels of octahedral structure. co : list Atomic coordinates of octahedral structure. save : str Name of image file to save. If this argument is not set by user, do not save a figure as image. Returns ------- None : None """ fig = plt.figure() ax = Axes3D(fig) # Plot atoms for i in range(len(co)): # Determine atomic number n = elements.check_atom(ao[i]) ax.scatter(co[i][0], co[i][1], co[i][2], marker='o', linewidths=0.5, edgecolors='black', color=elements.check_color(n), label=f"{ao[i]}", s=elements.check_radii(n) * 300) # Draw line for i in range(1, len(co)): merge = list(zip(co[0], co[i])) x, y, z = merge ax.plot(x, y, z, 'k-', color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = plt.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r'X', fontsize=15) ax.set_ylabel(r'Y', fontsize=15) ax.set_zlabel(r'Z', fontsize=15) ax.set_title('Octahedral structure', fontsize="12") ax.grid(True) # plt.axis('equal') if save != "not_save": plt.savefig('{0}.png'.format(save)) plt.show()
def find_metal(atom=None, coord=None): """ Count the number of metal center atom in complex. Parameters ---------- atom : list, None Full atomic labels of complex. coord : array_like, None Full atomic coordinates of complex. Returns ------- total_metal : int The total number of metal center atom. atom_metal : list Atomic labels of metal center atom. coord_metal : ndarray Atomic coordinates of metal center atom. See Also -------- octadist.src.elements.check_atom : Convert atomic number to atomic symbol and vice versa. Examples -------- >>> atom = ['Fe', 'N', 'N', 'N', 'N', 'N', 'N'] >>> coord = [[-1.95348286e+00, 4.51770478e+00, 1.47855811e+01], [-1.87618286e+00, 4.48070478e+00, 1.26484811e+01], [-3.90128286e+00, 5.27750478e+00, 1.40814811e+01], [-4.88286000e-03, 3.69060478e+00, 1.42392811e+01], [-2.18698286e+00, 4.34540478e+00, 1.69060811e+01], [-1.17538286e+00, 6.38340478e+00, 1.56457811e+01], [-2.75078286e+00, 2.50260478e+00, 1.51806811e+01]] >>> total_metal, atom_metal, coord_metal = find_metal(atom, coord) >>> total_metal 1 >>> atom_metal ['Fe'] >>> coord_metal [[-1.95348286 4.51770478 14.78558113]] """ if atom is None or coord is None: raise TypeError("find_metal needs two arguments: atom, coord") total_metal = 0 atom_metal = [] coord_metal = [] for i in range(len(atom)): number = elements.check_atom(atom[i]) if (21 <= number <= 30 or 39 <= number <= 48 or 57 <= number <= 80 or 89 <= number <= 109): total_metal += 1 atom_metal.append(atom[i]) coord_metal.append(coord[i]) coord_metal = np.asarray(coord_metal, dtype=np.float64) return total_metal, atom_metal, coord_metal
def plot_fit_plane(self): """ Display complex and two fit planes of two sets of ligand in molecule. """ ############### # Clear boxes # ############### self.box_angle1.delete(0, tk.END) self.box_angle2.delete(0, tk.END) self.box_eq1.delete(0, tk.END) self.box_eq2.delete(0, tk.END) ######################## # Find eq of the plane # ######################## xx, yy, z, abcd = plane.find_fit_plane(self.coord_A) plane_a = (xx, yy, z) a1, b1, c1, d1 = abcd self.box_eq1.insert( tk.INSERT, f"{a1:8.5f}x {b1:+8.5f}y {c1:+8.5f}z {d1:+8.5f} = 0") xx, yy, z, abcd = plane.find_fit_plane(self.coord_B) plane_b = (xx, yy, z) a2, b2, c2, d2 = abcd self.box_eq2.insert( tk.INSERT, f"{a2:8.5f}x {b2:+8.5f}y {c2:+8.5f}z {d2:+8.5f} = 0") #################################### # Calculate angle between 2 planes # #################################### angle = linear.angle_btw_planes(a1, b1, c1, a2, b2, c2) self.box_angle1.insert(tk.INSERT, f"{angle:10.6f}") # insert to box sup_angle = abs(180 - angle) # supplementary angle self.box_angle2.insert(tk.INSERT, f"{sup_angle:10.6f}") # insert to box ############### # Plot planes # ############### fig = plt.figure() # fig = plt.figure(figsize=(5, 4), dpi=100) ax = Axes3D(fig) # ax = fig.add_subplot(111, projection='3d') # Plot all atoms for i in range(len(self.coord)): # Determine atomic number n = elements.check_atom(self.atom[i]) ax.scatter( self.coord[i][0], self.coord[i][1], self.coord[i][2], marker="o", linewidths=0.5, edgecolors="black", picker=5, color=elements.check_color(n), label=f"{self.atom[i]}", s=elements.check_radii(n) * 300, ) atoms_pair = [] for i in range(len(self.bond_list)): get_atoms = self.bond_list[i] x, y, z = zip(*get_atoms) atoms = list(zip(x, y, z)) atoms_pair.append(atoms) # Draw line for i in range(len(atoms_pair)): merge = list(zip(atoms_pair[i][0], atoms_pair[i][1])) x, y, z = merge ax.plot(x, y, z, "k-", color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = fig.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r"X", fontsize=15) ax.set_ylabel(r"Y", fontsize=15) ax.set_zlabel(r"Z", fontsize=15) ax.set_title("Full complex", fontsize="12") ax.grid(True) # Plot plane A xx, yy, z = plane_a ax.plot_surface(xx, yy, z, alpha=0.2, color="green") # Plot plane B xx, yy, z = plane_b ax.plot_surface(xx, yy, z, alpha=0.2, color="red") # ax.set_xlim(-10, 10) # ax.set_ylim(-10, 10) # ax.set_zlim(0, 10) # plt.axis('equal') # plt.axis('off') plt.show()
def pick_atom(self, group): """ On-mouse pick atom and get XYZ coordinate. Parameters ---------- group : str Group A or B. """ fig = plt.figure() # fig = plt.figure(figsize=(5, 4), dpi=100) ax = Axes3D(fig) # ax = fig.add_subplot(111, projection='3d') # Plot all atoms for i in range(len(self.coord)): # Determine atomic number n = elements.check_atom(self.atom[i]) ax.scatter( self.coord[i][0], self.coord[i][1], self.coord[i][2], marker="o", linewidths=0.5, edgecolors="black", picker=5, color=elements.check_color(n), label=f"{self.atom[i]}", s=elements.check_radii(n) * 300, ) atoms_pair = [] for i in range(len(self.bond_list)): get_atoms = self.bond_list[i] x, y, z = zip(*get_atoms) atoms = list(zip(x, y, z)) atoms_pair.append(atoms) # Draw line for i in range(len(atoms_pair)): merge = list(zip(atoms_pair[i][0], atoms_pair[i][1])) x, y, z = merge ax.plot(x, y, z, "k-", color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = fig.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r"X", fontsize=15) ax.set_ylabel(r"Y", fontsize=15) ax.set_zlabel(r"Z", fontsize=15) ax.set_title("Full complex", fontsize="12") ax.grid(True) def insert_text(text, coord, group): """ Insert text in boxes. Parameters ---------- text : str Text. coord : list or array Coordinates. group : str Group A or B. """ if group == "A": self.box_1.insert(tk.INSERT, text + "\n") self.box_1.see(tk.END) self.coord_A.append(coord) elif group == "B": self.box_2.insert(tk.INSERT, text + "\n") self.box_2.see(tk.END) self.coord_B.append(coord) def on_pick(event): """ Pick point and get XYZ data Parameters ---------- event : object Event object for on-pick function. Examples -------- >>> def on_pick(event): >>> ... ind = event.ind >>> ... print("on_pick scatter:", ind, np.take(x, ind), np.take(y, ind)) """ ind = event.ind[0] x, y, z = event.artist._offsets3d for i in range(len(self.atom)): if x[ind] == self.coord[i][0]: if y[ind] == self.coord[i][1]: if z[ind] == self.coord[i][2]: atom = self.atom[i] break results = f"{i + 1} {atom} : {x[ind]} {y[ind]} {z[ind]}" coord = [x[ind], y[ind], z[ind]] insert_text(results, coord, group) # Highlight selected atom index = elements.check_atom(atom) ax.scatter( x[ind], y[ind], z[ind], marker="o", linewidths=0.5, edgecolors="orange", picker=5, alpha=0.5, color="yellow", s=elements.check_radii(index) * 400, ) # print(i+1, atom, x[ind], y[ind], z[ind]) fig.canvas.mpl_connect("pick_event", on_pick) # plt.axis('equal') # plt.axis('off') plt.show()
def plot_fit_plane(acf, coord_A, coord_B): """ Display complex and two fit planes of two sets of ligand in molecule. Parameters ---------- acf : list Atomic labels and coordinates of full complex. coord_A : list List of chunk of atoms, set A. coord_B : list List of chunk of atoms, set B. Returns ------- None : None """ ######################## # Find eq of the plane # ######################## xx, yy, z, abcd = calc_fit_plane(coord_A) plane_A = (xx, yy, z) a1, b1, c1, d1 = abcd xx, yy, z, abcd = calc_fit_plane(coord_B) plane_B = (xx, yy, z) a2, b2, c2, d2 = abcd #################################### # Calculate angle between 2 planes # #################################### angle = linear.angle_btw_planes(a1, b1, c1, a2, b2, c2) sup_angle = abs(180 - angle) # supplementary angle ############### # Plot planes # ############### fal, fcl = acf[0] fig = plt.figure() # fig = plt.figure(figsize=(5, 4), dpi=100) ax = Axes3D(fig) # ax = fig.add_subplot(111, projection='3d') # Plot all atoms for i in range(len(fcl)): # Determine atomic number n = elements.check_atom(fal[i]) ax.scatter(fcl[i][0], fcl[i][1], fcl[i][2], marker='o', linewidths=0.5, edgecolors='black', picker=5, color=elements.check_color(n), label=f"{fal[i]}", s=elements.check_radii(n) * 300) # Calculate distance bond_list = tools.find_bonds(fal, fcl) atoms_pair = [] for i in range(len(bond_list)): get_atoms = bond_list[i] x, y, z = zip(*get_atoms) atoms = list(zip(x, y, z)) atoms_pair.append(atoms) # Draw line for i in range(len(atoms_pair)): merge = list(zip(atoms_pair[i][0], atoms_pair[i][1])) x, y, z = merge ax.plot(x, y, z, 'k-', color="black", linewidth=2) # Set legend # Remove duplicate labels in legend. # Ref.https://stackoverflow.com/a/26550501/6596684 handles, labels = ax.get_legend_handles_labels() handle_list, label_list = [], [] for handle, label in zip(handles, labels): if label not in label_list: handle_list.append(handle) label_list.append(label) leg = fig.legend(handle_list, label_list, loc="lower left", scatterpoints=1, fontsize=12) # Fixed size of point in legend # Ref. https://stackoverflow.com/a/24707567/6596684 for i in range(len(leg.legendHandles)): leg.legendHandles[i]._sizes = [90] # Set axis ax.set_xlabel(r'X', fontsize=15) ax.set_ylabel(r'Y', fontsize=15) ax.set_zlabel(r'Z', fontsize=15) ax.set_title('Full complex', fontsize="12") ax.grid(True) # Plot plane A xx, yy, z = plane_A ax.plot_surface(xx, yy, z, alpha=0.2, color='green') # Plot plane B xx, yy, z = plane_B ax.plot_surface(xx, yy, z, alpha=0.2, color='red') # ax.set_xlim(-10, 10) # ax.set_ylim(-10, 10) # ax.set_zlim(0, 10) # plt.axis('equal') # plt.axis('off') plt.show()