-
Notifications
You must be signed in to change notification settings - Fork 0
/
aromatics.py
95 lines (86 loc) · 4.32 KB
/
aromatics.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import pandas as pd
import numpy as np
import os
from biopandas.pdb import PandasPdb
class AromaticsFormat:
"""Gera uma matriz com as coordenadas e todas as distâncias de par em par dos átomos,
também gera o aromatic arrays e o aromatic normals"""
def __init__(self, filename):
self.filename = filename
self.aromatic_pos = []
self.aromatic_points = []
self.invalids = []
self.aromatic_array = {}
self.aromatic_normals = {}
self.df_total = pd.DataFrame()
self.aminos = pd.DataFrame()
self.arom_phe_tyr = ['CG', 'CD1', 'CD2', 'CE1', 'CE2', 'CZ']
self.arom_trp = ['CD2', 'CE2', 'CE3', 'CZ2', 'CZ3', 'CH2']
def _formata_arquivo(self):
"""Formata o dataframe inicial usando o biopandas, cria um dataframe só com os aminoácidos
e os átomos necessários"""
file = open(self.filename, 'r')
new_name = f'{self.filename}new.pdb'
with open(new_name, 'w') as f:
for line in file:
if "ENDMDL" in line:
break
else:
f.write(line)
ppdb = PandasPdb()
ppdb.read_pdb(new_name)
os.remove(new_name)
atom = ppdb.df['ATOM']
hetatm = ppdb.df['HETATM']
# Cria um dataframe apenas com ATOM E HETATM
self.df_total = pd.concat([atom, hetatm], sort=False)
self.df_total = self.df_total.reset_index()
self.df_total = self.df_total.drop(['index'], axis=1)
# Gera uma nova coluna 'amin' que vai ter o 'id' da cadeia e o número do resíduo
self.df_total['amin'] = self.df_total['chain_id'] + ' ' + self.df_total['residue_number'].astype(str)
self.df_total = self.df_total.drop(['atom_number', 'b_factor', 'alt_loc', 'line_idx',
'occupancy', 'element_symbol', 'charge', 'insertion',
'segment_id', 'blank_1', 'blank_2', 'blank_3', 'blank_4',
'chain_id', 'residue_number'], axis=1)
self.aminos = self.df_total[self.df_total['residue_name'].isin(['TYR', 'PHE', 'TRP'])]
self.aminos = self.aminos.loc[
(self.aminos['residue_name'].isin(['TYR'])) & (self.aminos['atom_name'].isin(self.arom_phe_tyr)) |
(self.aminos['residue_name'].isin(['PHE'])) & (self.aminos['atom_name'].isin(self.arom_phe_tyr)) |
(self.aminos['residue_name'].isin(['TRP'])) & (self.aminos['atom_name'].isin(self.arom_trp))]
def _calcula_array(self, amin):
"""Calcula o aromaticpos e o aromaticpoints de um determinado Amin"""
df = self.aminos[self.aminos['amin'].isin([amin])]
self.aromatic_pos = [df.iloc[0]['x_coord'], df.iloc[0]['y_coord'], df.iloc[0]['z_coord']]
for index, linha in df.iterrows():
coordenada = self._gera_coord(linha)
self.aromatic_pos = [(x + y) / 2 for x, y in zip(self.aromatic_pos, coordenada)]
self.aromatic_array[amin] = self.aromatic_pos
if len(df) < 3:
self.invalids.append(amin)
else:
self.aromatic_points = self._gera_coord(df.iloc[0:3])
veca = np.subtract(self.aromatic_points[1], self.aromatic_points[0])
vecb = np.subtract(self.aromatic_points[2], self.aromatic_points[0])
self.aromatic_normals[amin] = np.cross(veca, vecb)
@staticmethod
def _gera_coord(linhas):
"""Retorna as coordenadas de uma determinada linha ou listas de linhas"""
coord = []
if isinstance(linhas, pd.DataFrame):
for index, linha in linhas.iterrows():
coord.append([linha['x_coord'], linha['y_coord'], linha['z_coord']])
else:
coord = [linhas['x_coord'], linhas['y_coord'], linhas['z_coord']]
return coord
def get_data(self):
"""Roda os métodos da classe e retorna o dataframe final com todas as distâncias
além do aromatic array e aromatic normals"""
self._formata_arquivo()
amin_list = list(dict.fromkeys(self.aminos['amin'].values))
for i in amin_list:
self._calcula_array(i)
return self.aromatic_array, self.aromatic_normals, self.invalids
if __name__ == '__main__':
af = AromaticsFormat('3og7.pdb')
array, normals, invalids = af.get_data()
print(array)