md-manager 2.3.1__py3-none-any.whl

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.
@@ -0,0 +1,324 @@
1
+ from ..conformation import chain_theta_angles, chain_gamma_angles
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from scipy.spatial import distance_matrix
6
+
7
+ __all__ = ["helix_criterion", "sheet_criterion", "predict_alpha_helix", "predict_beta_sheets"]
8
+
9
+ def helix_criterion(theta:pd.Series, gamma:pd.Series) -> pd.Series:
10
+ """
11
+ Identify the positions of alpha-helices in a protein structure based on conformational angles.
12
+
13
+ This function evaluates the conformational angles (`θ` and `γ`) of a protein's backbone
14
+ and returns a boolean Series indicating the positions where alpha-helices are present. The
15
+ identification is based on the CUTABI criteria for the angle thresholds.
16
+
17
+ The criteria used for identifying alpha-helices are presented here:
18
+ https://www.frontiersin.org/journals/molecular-biosciences/articles/10.3389/fmolb.2021.786123/full
19
+
20
+ Parameters:
21
+ theta : pandas.Series
22
+ A Series containing the θ (theta) angles for each residue in the protein structure, in degrees.
23
+ The index should correspond to the residue identifiers.
24
+ gamma : pandas.Series
25
+ A Series containing the γ (gamma) angles for each residue in the protein structure, in degrees.
26
+ The index must match the index of the `theta` Series.
27
+
28
+ Returns:
29
+ pandas.Series
30
+ A boolean Series with the same index as the input, where `True` indicates the position of an
31
+ alpha-helix (based on the CUTABI criteria) and `False` otherwise.
32
+
33
+ Raises:
34
+ ValueError
35
+ If the indexes of `theta` and `gamma` do not match.
36
+ KeyError
37
+ If either `theta` or `gamma` contains invalid or missing data (e.g., NaN values).
38
+
39
+ Example:
40
+ >>> import pandas as pd
41
+ >>> theta = pd.Series([85, 90, 100, 70], index=[1, 2, 3, 4])
42
+ >>> gamma = pd.Series([35, 50, 75, 25], index=[1, 2, 3, 4])
43
+ >>> helix_criterion(theta, gamma)
44
+ 1 True
45
+ 2 True
46
+ 3 True
47
+ 4 False
48
+ dtype: bool
49
+
50
+ Notes:
51
+ - Ensure that both `theta` and `gamma` angles are provided in degrees and correspond to
52
+ the same residues (i.e., have identical indexes).
53
+ - The criteria for `θ` and `γ` are specific to CUTABI and may not detect other types of
54
+ secondary structures.
55
+ - This function assumes a residue-level representation of the protein structure, where each
56
+ row in the input Series corresponds to a residue.
57
+ """
58
+ helix = pd.Series(False, index = theta.index)
59
+
60
+ # CUTABI parameters
61
+ theta_min, theta_max = (80.0, 105.0) # threshold for theta values
62
+ gamma_min, gamma_max = (30.0, 80.0) # threshold for gamma values
63
+
64
+ theta_criterion = (theta > theta_min) & (theta < theta_max)
65
+ gamma_criterion = (gamma > gamma_min) & (gamma < gamma_max)
66
+ tmp = pd.DataFrame({"Theta" : theta_criterion, "Gamma": gamma_criterion})
67
+
68
+ for win in tmp.rolling(4):
69
+ if win.Theta.all() & win.Gamma[1:-1].all():
70
+ helix[win.index] = True
71
+
72
+ return helix
73
+
74
+ def sheet_criterion(theta:pd.Series, gamma:pd.Series, xyz:pd.DataFrame) -> pd.Series:
75
+ """
76
+ Identify the positions of beta-sheets in a protein structure based on conformational angles and spatial coordinates.
77
+
78
+ This function evaluates the conformational angles (`θ` and `γ`) of a protein's backbone, as well as
79
+ the 3D coordinates of the Cα atoms, to determine the positions of beta-sheets. Beta-sheets are identified
80
+ based on specific ranges of conformational angles combined with spatial criteria derived from the Cα
81
+ atom positions.
82
+
83
+ The criteria used for identifying beta-sheets are presented here:
84
+ https://www.frontiersin.org/journals/molecular-biosciences/articles/10.3389/fmolb.2021.786123/full
85
+
86
+ Parameters:
87
+ theta : pandas.Series
88
+ A Series containing the θ (theta) angles for each residue in the protein structure, in degrees.
89
+ The index should correspond to the residue identifiers.
90
+ gamma : pandas.Series
91
+ A Series containing the γ (gamma) angles for each residue in the protein structure, in degrees.
92
+ The index must match the index of the `theta` Series.
93
+ xyz : pandas.DataFrame
94
+ A DataFrame containing the 3D coordinates of the Cα atoms for each residue in the structure.
95
+ The DataFrame must have the following columns:
96
+ - 'x', 'y', 'z': 3D Cartesian coordinates of the Cα atoms.
97
+ The index of the DataFrame must match the indexes of the `theta` and `gamma` Series.
98
+
99
+ Returns:
100
+ pandas.Series
101
+ A boolean Series with the same index as the input, where `True` indicates the position of a
102
+ beta-sheet and `False` otherwise.
103
+
104
+ Raises:
105
+ ValueError
106
+ If the indexes of `theta`, `gamma`, and `xyz` do not match.
107
+ KeyError
108
+ If the `xyz` DataFrame is missing required columns ['x', 'y', 'z'].
109
+
110
+ Example:
111
+ >>> import pandas as pd
112
+ >>> theta = pd.Series([-120, -130, -140, 70], index=[1, 2, 3, 4])
113
+ >>> gamma = pd.Series([120, 130, 140, 80], index=[1, 2, 3, 4])
114
+ >>> xyz = pd.DataFrame({
115
+ ... 'x': [0.0, 1.0, 2.0, 3.0],
116
+ ... 'y': [0.0, 0.5, 1.5, 2.0],
117
+ ... 'z': [0.0, -1.0, -1.5, -2.0]
118
+ ... }, index=[1, 2, 3, 4])
119
+ >>> sheet_criterion(theta, gamma, xyz)
120
+ 1 True
121
+ 2 True
122
+ 3 True
123
+ 4 False
124
+ dtype: bool
125
+
126
+ Notes:
127
+ - This function assumes the residue indexes in `theta`, `gamma`, and `xyz` align perfectly and represent
128
+ the same structure.
129
+
130
+ """
131
+ sheet = pd.Series(False, index = theta.index)
132
+
133
+ # CUTABI parameters :
134
+ theta_min, theta_max = (100.0, 155.0) # threshold for theta values
135
+ gamma_lim = 80.0 # threshold for abs(gamma) values
136
+
137
+ contact_threshold = 5.5 # threshold for K;I & K+1;I+-1 distances
138
+ contact_threshold2 = 6.8 # threshold for K+1;I+-2 distances
139
+
140
+ angle_criterion = pd.Series(False, index = sheet.index)
141
+
142
+ theta_criterion = (theta > theta_min) & (theta < theta_max)
143
+ gamma_criterion = gamma.abs() > gamma_lim
144
+ tmp = pd.DataFrame({"Theta" : theta_criterion, "Gamma": gamma_criterion})
145
+
146
+ for win in tmp.rolling(2):
147
+ if win.Theta.all() & win.Gamma[0:1].all():
148
+ angle_criterion[win.index] = True
149
+
150
+ inter_atom_distance = distance_matrix(xyz, xyz)
151
+
152
+ # Parallel sheet detection :
153
+ test1 = inter_atom_distance[:-1, :-2] < contact_threshold # K -I criterion
154
+ test2 = inter_atom_distance[1:, 1:-1] < contact_threshold # K+1-I+1 criterion
155
+ test3 = inter_atom_distance[1:,2:] < contact_threshold2 # K+1-I+2 criterion
156
+
157
+ distance_criterion = test1 & test2 & test3
158
+ I, K = np.where(distance_criterion)
159
+ for i, k in zip(I, K):
160
+ if k > i+2:
161
+ idx = [k, k+1, i, i+1]
162
+ if angle_criterion.iloc[idx].all():
163
+ sheet.iloc[idx] = True
164
+
165
+ # Anti-parallel sheet detection :
166
+ test1 = inter_atom_distance[:-1, 2:] < contact_threshold # K - I criterion
167
+ test3 = inter_atom_distance[1:,:-2] < contact_threshold2 # K+1-I-2 criterion
168
+
169
+ distance_criterion = test1 & test2 & test3
170
+ I, K = np.where(distance_criterion)
171
+ I += 2 # because test1[0, 0] -> k = 0, i = 2
172
+ for i, k in zip(I, K):
173
+ if k > i+2:
174
+ idx = [k, k+1, i, i+1]
175
+ if angle_criterion.iloc[idx].all():
176
+ sheet.iloc[idx] = True
177
+
178
+ return sheet
179
+
180
+ def predict_alpha_helix(df:pd.DataFrame) -> pd.Series:
181
+ """
182
+ Predict the positions of alpha-helices in a protein structure using the CUTABI criterion.
183
+
184
+ This function calculates the conformational angles (`θ` and `γ`) for each residue in the input
185
+ DataFrame based on the provided 3D coordinates (x, y, z) of the Cα atoms. The calculated angles
186
+ are then passed to the `helix_criterion` function to predict regions of alpha-helical secondary
187
+ structure. The prediction is based on the following thresholds, as defined by the CUTABI criterion.
188
+
189
+ Parameters:
190
+ df : pandas.DataFrame
191
+ A DataFrame containing the 3D coordinates for the Cα atoms of the protein structure. The DataFrame
192
+ must include the following columns:
193
+ - 'x', 'y', 'z': The 3D Cartesian coordinates of the Cα atoms.
194
+ The index should correspond to the residue identifiers.
195
+ - Optional columns required atomic name selection (e.g., 'name').
196
+
197
+ Returns:
198
+ pandas.Series
199
+ A boolean Series with the same index as the input DataFrame, where `True` indicates the positions
200
+ of alpha-helices (based on the CUTABI criterion) and `False` otherwise.
201
+
202
+ Raises:
203
+ KeyError
204
+ If the input DataFrame is missing required columns ['x', 'y', 'z'].
205
+
206
+ ValueError
207
+ If the number of residues or coordinates is insufficient for computing the conformational angles.
208
+
209
+ Example:
210
+ >>> import pandas as pd
211
+ >>> data = pd.DataFrame({
212
+ ... 'x': [0.0, 1.0, 2.0, 3.0],
213
+ ... 'y': [0.0, 0.5, 1.5, 2.0],
214
+ ... 'z': [0.0, -1.0, -1.5, -2.0]
215
+ ... }, index=[1, 2, 3, 4])
216
+ >>> predict_alpha_helix(data)
217
+ 1 True
218
+ 2 True
219
+ 3 True
220
+ 4 False
221
+ dtype: bool
222
+
223
+ See Also:
224
+ - `helix_criterion`: The function used to evaluate the CUTABI criterion for alpha-helices based on
225
+ the angles `θ` and `γ`.
226
+
227
+ """
228
+ alpha = pd.Series(False, index=df.index)
229
+
230
+ if not "name" in df:
231
+ CA = df.copy()
232
+ else:
233
+ names = set(df.name)
234
+ names.remove("CA")
235
+ if len(names) > 0:
236
+ CA = df.query("name == 'CA'")
237
+ else:
238
+ CA = df.copy()
239
+
240
+ if not "chain" in df:
241
+ CA["chain"] = "A"
242
+
243
+ for _, chain in CA.groupby("chain"):
244
+ theta = chain_theta_angles(chain)
245
+ gamma = chain_gamma_angles(chain)
246
+ alpha_chain = helix_criterion(theta, gamma)
247
+
248
+ alpha[alpha_chain.index] = alpha_chain.values
249
+
250
+ return alpha
251
+
252
+ def predict_beta_sheets(df:pd.DataFrame) -> pd.Series:
253
+ """
254
+ Predict the positions of beta-sheets in a protein structure using the CUTABI criterion.
255
+
256
+ This function calculates the conformational angles (`θ` and `γ`) as well as inter-atomic distances for each residue in the input
257
+ DataFrame based on the provided 3D coordinates (x, y, z) of the Cα atoms. The calculated angles
258
+ are then passed to the `sheet_criterion` function to predict regions of alpha-helical secondary
259
+ structure. The prediction is based on the following thresholds, as defined by the CUTABI criterion.
260
+
261
+ Parameters:
262
+ df : pandas.DataFrame
263
+ A DataFrame containing the 3D coordinates for the Cα atoms of the protein structure. The DataFrame
264
+ must include the following columns:
265
+ - 'x', 'y', 'z': The 3D Cartesian coordinates of the Cα atoms.
266
+ The index should correspond to the residue identifiers.
267
+ - Optional columns required atomic name selection (e.g., 'name').
268
+
269
+ Returns:
270
+ pandas.Series
271
+ A boolean Series with the same index as the input DataFrame, where `True` indicates the positions
272
+ of alpha-helices (based on the CUTABI criterion) and `False` otherwise.
273
+
274
+ Raises:
275
+ KeyError
276
+ If the input DataFrame is missing required columns ['x', 'y', 'z'].
277
+
278
+ ValueError
279
+ If the number of residues or coordinates is insufficient for computing the conformational angles.
280
+
281
+ Example:
282
+ >>> import pandas as pd
283
+ >>> data = pd.DataFrame({
284
+ ... 'x': [0.0, 1.0, 2.0, 3.0],
285
+ ... 'y': [0.0, 0.5, 1.5, 2.0],
286
+ ... 'z': [0.0, -1.0, -1.5, -2.0]
287
+ ... }, index=[1, 2, 3, 4])
288
+ >>> predict_alpha_helix(data)
289
+ 1 True
290
+ 2 True
291
+ 3 True
292
+ 4 False
293
+ dtype: bool
294
+
295
+ See Also:
296
+ - `sheet_criterion`: The function used to evaluate the CUTABI criterion for beta-sheets based on
297
+ the angles `θ` and `γ`.
298
+
299
+ """
300
+ beta = pd.Series(False, index=df.index)
301
+
302
+ if not "name" in df:
303
+ CA = df.copy()
304
+ else:
305
+ names = set(df.name)
306
+ names.remove("CA")
307
+ if len(names) > 0:
308
+ CA = df.query("name == 'CA'")
309
+ else:
310
+ CA = df.copy()
311
+
312
+ if not "chain" in df:
313
+ CA["chain"] = "A"
314
+
315
+ for _, chain in CA.groupby("chain"):
316
+ theta = chain_theta_angles(chain)
317
+ gamma = chain_gamma_angles(chain)
318
+ xyz = chain[["x", "y", "z"]]
319
+ beta_chain = sheet_criterion(theta, gamma, xyz)
320
+
321
+ beta[beta_chain.index] = beta_chain.values
322
+
323
+ return beta
324
+
@@ -0,0 +1 @@
1
+ from .CUTABI import *
@@ -0,0 +1,151 @@
1
+ from ..df_operations import chain_theta_angles, chain_gamma_angles, check_chain_validity, InvalidChainException
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from scipy.spatial import distance_matrix
6
+
7
+ def helix_criterion(theta:pd.Series, gamma:pd.Series) -> pd.Series:
8
+ """
9
+ Takes the conformational angles of a single chain and returns a Series of boolean that indicates the position of alpha-helices.
10
+
11
+ Before calling this method, please make sure that the indexes of both Series are identical.
12
+ """
13
+ helix = pd.Series(False, index = theta.index)
14
+
15
+ # CUTABI parameters
16
+ theta_min, theta_max = (80.0, 105.0) # threshold for theta values
17
+ gamma_min, gamma_max = (30.0, 80.0) # threshold for gamma values
18
+
19
+ theta_criterion = (theta > theta_min) & (theta < theta_max)
20
+ gamma_criterion = (gamma > gamma_min) & (gamma < gamma_max)
21
+ tmp = pd.DataFrame({"Theta" : theta_criterion, "Gamma": gamma_criterion})
22
+
23
+ for win in tmp.rolling(4):
24
+ if win.Theta.all() & win.Gamma[1:-1].all():
25
+ helix[win.index] = True
26
+
27
+ return helix
28
+
29
+ def sheet_criterion(theta:pd.Series, gamma:pd.Series, xyz:pd.DataFrame) -> pd.Series:
30
+ """
31
+ Takes the conformational angles of a single chain as well as the coordinates of the CA atoms and returns a Series of boolean that indicates the position of beta-sheets.
32
+
33
+ Before calling this method, please make sure that the indexes of both Series and DataFrame are identical.
34
+ """
35
+ sheet = pd.Series(False, index = theta.index)
36
+
37
+ # CUTABI parameters :
38
+ theta_min, theta_max = (100.0, 155.0) # threshold for theta values
39
+ gamma_lim = 80.0 # threshold for abs(gamma) values
40
+
41
+ contact_threshold = 5.5 # threshold for K;I & K+1;I+-1 distances
42
+ contact_threshold2 = 6.8 # threshold for K+1;I+-2 distances
43
+
44
+ angle_criterion = pd.Series(False, index = sheet.index)
45
+
46
+ theta_criterion = (theta > theta_min) & (theta < theta_max)
47
+ gamma_criterion = gamma.abs() > gamma_lim
48
+ tmp = pd.DataFrame({"Theta" : theta_criterion, "Gamma": gamma_criterion})
49
+
50
+ for win in tmp.rolling(2):
51
+ if win.Theta.all() & win.Gamma[0:1].all():
52
+ angle_criterion[win.index] = True
53
+
54
+ inter_atom_distance = distance_matrix(xyz, xyz)
55
+
56
+ # Parallel sheet detection :
57
+ test1 = inter_atom_distance[:-1, :-2] < contact_threshold # K -I criterion
58
+ test2 = inter_atom_distance[1:, 1:-1] < contact_threshold # K+1-I+1 criterion
59
+ test3 = inter_atom_distance[1:,2:] < contact_threshold2 # K+1-I+2 criterion
60
+
61
+ distance_criterion = test1 & test2 & test3
62
+ I, K = np.where(distance_criterion)
63
+ for i, k in zip(I, K):
64
+ if k > i+2:
65
+ idx = [k, k+1, i, i+1]
66
+ if angle_criterion.iloc[idx].all():
67
+ sheet.iloc[idx] = True
68
+
69
+ # Anti-parallel sheet detection :
70
+ test1 = inter_atom_distance[:-1, 2:] < contact_threshold # K - I criterion
71
+ test3 = inter_atom_distance[1:,:-2] < contact_threshold2 # K+1-I-2 criterion
72
+
73
+ distance_criterion = test1 & test2 & test3
74
+ I, K = np.where(distance_criterion)
75
+ I += 2 # because test1[0, 0] -> k = 0, i = 2
76
+ for i, k in zip(I, K):
77
+ if k > i+2:
78
+ idx = [k, k+1, i, i+1]
79
+ if angle_criterion.iloc[idx].all():
80
+ sheet.iloc[idx] = True
81
+
82
+ return sheet
83
+
84
+ def check_df_infos(df:pd.DataFrame) -> None:
85
+ if not "chain" in df:
86
+ df["chain"] = "A"
87
+
88
+ for _, tmp in df.groupby("chain"):
89
+ check_chain_validity(tmp)
90
+
91
+
92
+ def predict_alpha_helix(df:pd.DataFrame) -> pd.Series:
93
+ """
94
+ Uses CUTABI criterion to predict the position of alpha-helices.
95
+ """
96
+ alpha = pd.Series(False, index=df.index)
97
+
98
+ if not "name" in df:
99
+ CA = df.copy()
100
+ else:
101
+ names = set(df.name)
102
+ names.remove("CA")
103
+ if len(names) > 0:
104
+ CA = df.query("name == 'CA'")
105
+ else:
106
+ CA = df.copy()
107
+
108
+
109
+ check_df_infos(CA)
110
+
111
+ for _, chain in CA.groupby("chain"):
112
+ theta = chain_theta_angles(chain)
113
+ gamma = chain_gamma_angles(chain)
114
+ alpha_chain = helix_criterion(theta, gamma)
115
+
116
+ alpha[alpha_chain.index] = alpha_chain.values
117
+
118
+ return alpha
119
+
120
+ def predict_beta_sheets(df:pd.DataFrame) -> pd.Series:
121
+ """
122
+ Uses CUTABI criterion to predict the position of alpha-helices.
123
+ """
124
+ beta = pd.Series(False, index=df.index)
125
+
126
+ if not "name" in df:
127
+ CA = df.copy()
128
+ else:
129
+ names = set(df.name)
130
+ names.remove("CA")
131
+ if len(names) > 0:
132
+ CA = df.query("name == 'CA'")
133
+ else:
134
+ CA = df.copy()
135
+
136
+
137
+ check_df_infos(CA)
138
+
139
+ for _, chain in CA.groupby("chain"):
140
+ theta = chain_theta_angles(chain)
141
+ gamma = chain_gamma_angles(chain)
142
+ xyz = chain[["x", "y", "z"]]
143
+ beta_chain = sheet_criterion(theta, gamma, xyz)
144
+
145
+ beta[beta_chain.index] = beta_chain.values
146
+
147
+ return beta
148
+
149
+
150
+
151
+
@@ -0,0 +1,32 @@
1
+ from .Traj_ import Traj
2
+ from MDAnalysis.coordinates.GRO import GROWriter
3
+
4
+ class GRO(Traj):
5
+ default_params = dict(
6
+ # Read/Write mode:
7
+ mode = "r",
8
+
9
+ # Topology records:
10
+ return_topology = True,
11
+ return_alt = False,
12
+ return_chain = False,
13
+ return_occupancy = False,
14
+ return_b = False,
15
+ return_segi = False,
16
+ return_e = False,
17
+ return_q = False,
18
+ return_m = False,
19
+
20
+ # Data records
21
+ return_velocity = False,
22
+ #return_forces = False # TODO
23
+
24
+ # Secondary structures:
25
+ return_alpha = False,
26
+ return_beta = False,
27
+ ss_method = "CUTABI"
28
+ )
29
+
30
+ def save(self, filename:str):
31
+ with GROWriter(filename) as gro:
32
+ gro.write(self.atoms)
@@ -0,0 +1,100 @@
1
+ from .Traj_ import Traj
2
+ from MDAnalysis.coordinates.PDB import PDBWriter
3
+
4
+ import pandas as pd
5
+ import sys
6
+ from urllib.request import urlopen
7
+
8
+ class PDB(Traj):
9
+ default_params = dict(
10
+ # Read/Write mode:
11
+ mode = "r",
12
+
13
+ # Topology records:
14
+ return_topology = True,
15
+ return_alt = True,
16
+ return_chain = True,
17
+ return_occupancy = True,
18
+ return_b = False,
19
+ return_segi = True,
20
+ return_e = False,
21
+ return_q = False,
22
+ return_m = False,
23
+
24
+ # Data records
25
+ return_velocity = False,
26
+ #return_forces = False # TODO
27
+
28
+ # Secondary structures:
29
+ return_alpha = False,
30
+ return_beta = False,
31
+ ss_method = "CUTABI"
32
+ )
33
+
34
+ def save(self, filename:str, multiframe=False):
35
+ with PDBWriter(filename, multiframe=multiframe) as pdb:
36
+ if multiframe:
37
+ self = iter(self)
38
+ for u in self.frame:
39
+ pdb.write(u)
40
+
41
+ else:
42
+ pdb.write(self.atoms)
43
+
44
+ def read_format(line:str) -> tuple[str, str, str, str, int, str, float, float, float, float, float, float, str, str, str]:
45
+ """
46
+ Parses a line from a PDB file to extract atomic data.
47
+
48
+ Args:
49
+ line (str): A single line from the PDB file, formatted according
50
+ to the PDB specification.
51
+
52
+ Returns:
53
+ tuple[str, str, str, str, int, str, float, float, float, float,
54
+ float, float, str, str, str]: A tuple containing atom information,
55
+ including:
56
+ - Atom name
57
+ - Alternate location indicator
58
+ - Residue name
59
+ - Chain identifier
60
+ - Residue sequence number
61
+ - Insertion code
62
+ - X, Y, and Z coordinates
63
+ - Occupancy and temperature factor
64
+ - Segment identifier, element symbol, and charge
65
+ """
66
+ return (
67
+ line[:6].strip(),
68
+ #int(line[6:11].strip()),
69
+ line[12:16].strip(), # Atom name
70
+ line[16:17].strip(), # Alternate location indicator
71
+ line[17:20].strip() , # Residue name
72
+ line[21:22].strip(), # Chain identifier
73
+ int(line[22:26].strip()), # Residue sequence number
74
+ line[26:27].strip(), # Insertion code
75
+ float(line[30:38].strip()), # X coordinate
76
+ float(line[38:46].strip()), # Y coordinate
77
+ float(line[46:54].strip()), # Z coordinate
78
+ float(line[54:60].strip()) if line[54:60].strip() != "" else 1.0, # Occupancy
79
+ float(line[60:66].strip()) if line[60:66].strip() != "" else 0.0, # Temperature factor
80
+ line[72:76].strip(), # Segment identifier
81
+ line[76:78].strip(), # Element symbol
82
+ line[78:80].strip() # Charge on the atom
83
+ )
84
+
85
+ def fetch_PDB(pdb_code:str, atom_only = False) -> pd.DataFrame:
86
+ url = f"https://files.rcsb.org/download/{pdb_code.lower()}.pdb"
87
+ response = urlopen(url)
88
+
89
+ txt = response.read()
90
+ lines = (txt.decode("utf-8") if sys.version_info[0] >= 3 else txt.decode("ascii")).splitlines()
91
+
92
+ data = [
93
+ read_format(line) for line in lines if line.startswith("ATOM") or (not atom_only and line.startswith("HETATM"))
94
+ ]
95
+
96
+ df = pd.DataFrame(data, columns = ["record_name", "name", "alt", "resn", "chain", "resi", "insertion", "x", "y", "z", "occupancy", "b", "segi", "e", "q"])
97
+ df.index.name = "atom_id"
98
+ df.index += 1
99
+
100
+ return df