EZ4Fanta commited on
Commit
43c59ae
·
1 Parent(s): b2f19ba

add suport to cif

Browse files
Files changed (2) hide show
  1. app.py +2 -29
  2. utils.py +45 -10
app.py CHANGED
@@ -13,37 +13,10 @@ default_file = "static/test.pdb"
13
  TEMP_DIR = "static/tmp/"
14
  os.makedirs(TEMP_DIR, exist_ok=True)
15
 
16
- # # 保存全局信息以便交互
17
- # structure_cache = gr.State()
18
- # contact_cache = None
19
-
20
- def read_file(file_path):
21
- if file_path is None:
22
- return "<b style='color:red'>未提供结构文件</b>"
23
-
24
- try:
25
- with open(file_path, "r") as f:
26
- structure_str = f.read()
27
- except Exception as e:
28
- return f"<b style='color:red'>读取文件失败: {e}</b>"
29
-
30
- # file_format = file_path.split(".")[-1]
31
- summary = analyze_structure_combined(file_path)
32
- entity_color_dict = build_entity_color_dict(list(summary.keys()))
33
-
34
- # 缓存用于后续交互
35
- structure_dict = {
36
- "structure_str": structure_str,
37
- "summary": summary,
38
- "entity_color_dict": entity_color_dict
39
- }
40
-
41
- return structure_str, summary, entity_color_dict, structure_dict
42
-
43
 
44
  def render_structure(structure_str, summary, entity_color_dict, add_label=True):
45
  view = py3Dmol.view(width=233, height=233)
46
- view.addModel(structure_str, 'pdb')
47
  set_default_styles(view, summary, entity_color_dict, add_label=add_label)
48
  view.zoomTo()
49
  return view
@@ -174,7 +147,7 @@ with gr.Blocks() as demo:
174
  )
175
  pdb_btn = gr.Button("获取结构", scale=1)
176
 
177
- file_input = gr.File(label="或直接上传PDB文件", file_types=[".pdb"])
178
  with gr.Column(scale=2):
179
  with gr.Row():
180
  entity_selector = gr.Dropdown(choices=[], interactive=True, multiselect=True, label="选择实体", scale=2)
 
13
  TEMP_DIR = "static/tmp/"
14
  os.makedirs(TEMP_DIR, exist_ok=True)
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  def render_structure(structure_str, summary, entity_color_dict, add_label=True):
18
  view = py3Dmol.view(width=233, height=233)
19
+ view.addModel(structure_str) # 不指定类型似乎可以自动识别
20
  set_default_styles(view, summary, entity_color_dict, add_label=add_label)
21
  view.zoomTo()
22
  return view
 
147
  )
148
  pdb_btn = gr.Button("获取结构", scale=1)
149
 
150
+ file_input = gr.File(label="或直接上传PDB文件", file_types=[".pdb", ".cif", ".ent"])
151
  with gr.Column(scale=2):
152
  with gr.Row():
153
  entity_selector = gr.Dropdown(choices=[], interactive=True, multiselect=True, label="选择实体", scale=2)
utils.py CHANGED
@@ -4,13 +4,13 @@ import hashlib
4
  import numpy as np
5
 
6
  from tempfile import NamedTemporaryFile
7
-
8
- from Bio.PDB import MMCIFParser, PDBParser, PDBList
9
  from collections import defaultdict
10
  import colorsys
11
  import hashlib
12
  from Bio.PDB.NeighborSearch import NeighborSearch
13
-
14
 
15
  NUCLEIC_ACIDS = {
16
  "A", "G", "C", "U", "T",
@@ -112,7 +112,17 @@ def classify_residue(residue):
112
 
113
  def analyze_structure_combined(file_path):
114
  if file_path.endswith(".cif"):
 
 
 
 
 
 
 
 
 
115
  parser = MMCIFParser(QUIET=True)
 
116
  elif file_path.endswith(".pdb") or file_path.endswith(".ent"):
117
  parser = PDBParser(QUIET=True)
118
  else:
@@ -149,6 +159,30 @@ def analyze_structure_combined(file_path):
149
  ))
150
  return sorted_summary
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  def extract_contact_residues(summary, selected_keys, cutoff=3.5):
153
  entity_atoms = {key: [] for key in selected_keys}
154
  atom_to_residue_info = {}
@@ -247,7 +281,7 @@ def extract_polar_contacts(summary, contact_summary, cutoff=3.5, angle_cutoff=12
247
 
248
  def set_default_styles(viewer, summary, entity_color_dict,
249
  add_label=True):
250
- # viewer.setStyle({'hetflag': True}, {"stick": {}})
251
  for entity, color in entity_color_dict.items():
252
  label_style = {
253
  'fontOpacity':1,
@@ -260,18 +294,19 @@ def set_default_styles(viewer, summary, entity_color_dict,
260
  if "(protein)" in entity.lower():
261
  # 提取链ID
262
  chain_id = entity.split()[1]
263
- if chain_id == 'A':
264
- print(summary[entity])
265
- viewer.setStyle({'chain': chain_id}, {'cartoon': {'color': color}})
 
266
  if add_label:
267
  viewer.addLabel(entity, label_style, {'chain':chain_id})
268
  elif '(dna)' in entity.lower() or '(rna)' in entity.lower():
269
  # 提取链ID
270
  chain_id = entity.split()[1]
271
- if chain_id == 'T':
272
- print(summary[entity])
273
  viewer.setStyle({'chain': chain_id},
274
- {'cartoon': {'color': 'blue', 'opacity': 0.8}}) # 碱基和磷酸用stick)
 
 
275
  if add_label:
276
  viewer.addLabel(entity, label_style, {'chain':chain_id})
277
 
 
4
  import numpy as np
5
 
6
  from tempfile import NamedTemporaryFile
7
+ from io import StringIO
8
+ from Bio.PDB import MMCIFParser, PDBParser, PDBIO
9
  from collections import defaultdict
10
  import colorsys
11
  import hashlib
12
  from Bio.PDB.NeighborSearch import NeighborSearch
13
+ from Bio.PDB.DSSP import DSSP
14
 
15
  NUCLEIC_ACIDS = {
16
  "A", "G", "C", "U", "T",
 
112
 
113
  def analyze_structure_combined(file_path):
114
  if file_path.endswith(".cif"):
115
+ with open(file_path, 'r') as f:
116
+ content = f.read()
117
+ # 如果缺少 data_ 开头,就加上一个默认块名
118
+ if not content.lstrip().startswith("data_"):
119
+ content = "data_auto\n" + content
120
+ # 3. 写入临时 mmCIF 文件
121
+ with NamedTemporaryFile(suffix=".cif", delete=False, mode='w') as tmp:
122
+ tmp.write(content)
123
+ file_path = tmp.name
124
  parser = MMCIFParser(QUIET=True)
125
+
126
  elif file_path.endswith(".pdb") or file_path.endswith(".ent"):
127
  parser = PDBParser(QUIET=True)
128
  else:
 
159
  ))
160
  return sorted_summary
161
 
162
+ def read_file(file_path):
163
+ if file_path is None:
164
+ return "<b style='color:red'>未提供结构文件</b>"
165
+
166
+ try:
167
+ with open(file_path, "r") as f:
168
+ structure_str = f.read()
169
+ except Exception as e:
170
+ return f"<b style='color:red'>读取文件失败: {e}</b>"
171
+
172
+ # file_format = file_path.split(".")[-1]
173
+ summary = analyze_structure_combined(file_path)
174
+ entity_color_dict = build_entity_color_dict(list(summary.keys()))
175
+
176
+ # 缓存用于后续交互
177
+ structure_dict = {
178
+ "structure_str": structure_str,
179
+ "summary": summary,
180
+ "entity_color_dict": entity_color_dict
181
+ }
182
+
183
+ return structure_str, summary, entity_color_dict, structure_dict
184
+
185
+
186
  def extract_contact_residues(summary, selected_keys, cutoff=3.5):
187
  entity_atoms = {key: [] for key in selected_keys}
188
  atom_to_residue_info = {}
 
281
 
282
  def set_default_styles(viewer, summary, entity_color_dict,
283
  add_label=True):
284
+ viewer.setStyle({'hetflag': True}, {"stick": {}})
285
  for entity, color in entity_color_dict.items():
286
  label_style = {
287
  'fontOpacity':1,
 
294
  if "(protein)" in entity.lower():
295
  # 提取链ID
296
  chain_id = entity.split()[1]
297
+ viewer.setStyle({'chain': chain_id},
298
+ {'cartoon': {'arrows': True,
299
+ 'color': color,
300
+ 'opacity': 0.9}})
301
  if add_label:
302
  viewer.addLabel(entity, label_style, {'chain':chain_id})
303
  elif '(dna)' in entity.lower() or '(rna)' in entity.lower():
304
  # 提取链ID
305
  chain_id = entity.split()[1]
 
 
306
  viewer.setStyle({'chain': chain_id},
307
+ {'cartoon': {'color': color,
308
+ 'nucleicAcid': True,
309
+ 'opacity': 0.8}}) # 碱基和磷酸用stick)
310
  if add_label:
311
  viewer.addLabel(entity, label_style, {'chain':chain_id})
312