所以我一直在尝试用Python可视化蛋白质,所以我在youtube上找到了一些教程,最后我找到了一个教程,教你如何可视化来自COVID-19病毒的蛋白质,所以我去设置anaconda,让 jupyter 笔记本工作 vscode,并从 PDB 数据库下载必要的文件,并确保它们与我的笔记本位于同一目录中,但是当我运行 nglview.show_biopython(struct) 函数时,我得到一个 ValueError: I/ O 对关闭的文件进行操作。我很困惑这是我第一次使用 jupyter 笔记本,所以也许我遗漏了一些东西,我不知道。
这就是代码的样子
from Bio.PDB import *
import nglview as nv
parser = PDBParser()
structure = parser.get_structure("6YYT", "6YYT.pdb")
view = nv.show_biopython(structure)
这是错误
Output exceeds the size limit. Open the full output data in a text editor
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_1728\2743687014.py in <module>
----> 1 view = nv.show_biopython(structure)
c:\Users\jerem\anaconda3\lib\site-packages\nglview\show.py in show_biopython(entity, **kwargs)
450 '''
451 entity = BiopythonStructure(entity)
--> 452 return NGLWidget(entity, **kwargs)
453
454
c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in __init__(self, structure, representations, parameters, **kwargs)
243 else:
244 if structure is not None:
--> 245 self.add_structure(structure, **kwargs)
246
247 if representations:
c:\Users\jerem\anaconda3\lib\site-packages\nglview\widget.py in add_structure(self, structure, **kwargs)
1111 if not isinstance(structure, Structure):
1112 raise ValueError(f'{structure} is not an instance of Structure')
-> 1113 self._load_data(structure, **kwargs)
1114 self._ngl_component_ids.append(structure.id)
1115 if self.n_components > 1:
...
--> 200 return io_str.getvalue()
201
202
ValueError: I/O operation on closed file
我仅在使用 nglview.show_biopython 时出现此错误,当我运行 get_struct() 函数时,它可以很好地读取文件。我可以很好地可视化其他分子,或者可能是因为我使用的是 ASE 库而不是文件。我不知道,这就是我来这里的原因。
更新:最近我发现我可以使用 nglview.show_file() 而不是使用 nglview.show_biopython() 来可视化蛋白质。尽管我现在可以可视化蛋白质并且从技术上讲我的问题已经解决,但我仍然想知道为什么 show_biopython() 函数无法正常工作。
我还想出了另一种方法来解决这个问题。回到我正在谈论的教程后,我看到它是在 2021 年制作的。看到这个后,我想知道我们是否使用每个包的相同版本,事实证明我们不是。我不确定他们使用的是哪个版本的 nglview,但他们使用的是 biopython 1.79,这是 2021 年的最新版本,而我使用的是 biopython 1.80。在使用 biopython 1.80 时,我收到了上面看到的错误。但现在我使用 biopython 1.79 我得到了这个:
file = "6YYT.pdb"
parser = PDBParser()
structure = parser.get_structure("6YYT", file)
structure
view = nv.show_biopython(structure)
view
c:\Users\jerem\anaconda3\lib\site-packages\Bio\PDB\StructureBuilder.py:89:
PDBConstructionWarning: WARNING: Chain A is discontinuous at line 12059.
warnings.warn(
所以我猜biopython 1.80 出了问题,所以我会坚持使用 1.79
我也遇到过类似的问题:
from Bio.PDB import *
import nglview as nv
parser = PDBParser(QUIET = True)
structure = parser.get_structure("2ms2", "2ms2.pdb")
save_pdb = PDBIO()
save_pdb.set_structure(structure)
save_pdb.save('pdb_out.pdb')
view = nv.show_biopython(structure)
view
错误就像问题中一样:
.................site-packages/nglview/adaptor.py:201, in BiopythonStructure.get_structure_string(self)
199 io_str = StringIO()
200 io_pdb.save(io_str)
--> 201 return io_str.getvalue()
ValueError: I/O operation on closed file
我修改了
site-packages/nglview/adaptor.py:201, in BiopythonStructure.get_structure_string(self)
:
def get_structure_string(self):
from Bio.PDB import PDBIO
from io import StringIO
io_pdb = PDBIO()
io_pdb.set_structure(self._entity)
io_str = StringIO()
io_pdb.save(io_str)
return io_str.getvalue()
与:
def get_structure_string(self):
from Bio.PDB import PDBIO
import mmap
io_pdb = PDBIO()
io_pdb.set_structure(self._entity)
mo = mmap_str()
io_pdb.save(mo)
return mo.read()
并在同一个文件中添加了这个新类
mmap_str()
:
import mmap
import copy
class mmap_str():
import mmap #added import at top
instance = None
def __init__(self):
self.mm = mmap.mmap(-1, 2)
self.a = ''
b = '\n'
self.mm.write(b.encode(encoding = 'utf-8'))
self.mm.seek(0)
#print('self.mm.read().decode() ',self.mm.read().decode(encoding = 'utf-8'))
self.mm.seek(0)
def __new__(cls, *args, **kwargs):
if not isinstance(cls.instance, cls):
cls.instance = object.__new__(cls)
return cls.instance
def write(self, string):
self.a = str(copy.deepcopy(self.mm.read().decode(encoding = 'utf-8'))).lstrip('\n')
self.mm.seek(0)
#print('a -> ', self.a)
len_a = len(self.a)
self.mm = mmap.mmap(-1, len(self.a)+len(string))
#print('a :', self.a)
#print('len self.mm ', len(self.mm))
#print('lenght string : ', len(string))
#print(bytes((self.a+string).encode()))
self.mm.write(bytes((self.a+string).encode()))
self.mm.seek(0)
#print('written once ')
#self.mm.seek(0)
def read(self):
self.mm.seek(0)
a = self.mm.read().decode().lstrip('\n')
self.mm.seek(0)
return a
def __enter__(self):
return self
def __exit__(self, *args):
pass
如果我取消注释打印语句,我会得到:
IOPub data rate exceeded.
The notebook server will temporarily stop sending output
to the client in order to avoid crashing it.
错误,但是将它们注释掉我得到:
使用
nglview.show_file(filename)
时我得到:
这是因为,从
pdb_out.pdb
文件中可以看出
由我的代码输出,
Biopytho.PDB.PDBParser.get_structure(name , filename)
不检索负责生成完整CRYSTALLOGRAPHIC SYMMETRY/或biopython无法处理它的pdb标头(对此不确定,如果您了解得更好,请帮助),而只是坐标。
还是不明白这是怎么回事:
--> 201 return io_str.getvalue()
ValueError: I/O operation on closed file
这可能与木星 ipykernal 有关吗?希望有人能对此有更多的了解,不知道框架是如何运行的,但绝对与普通的 python 解释器不同。举个例子:
我的 Python virtualenv 之一中的相同代码将永远运行,因此可能是 ipykernel 不喜欢
StringIO()
或对它们做了一些奇怪的事情?
好的,感谢下面答案中的提示,我去检查了 github 存储库中的 PDBIO.py 版本 Biopython 1.80 并比较了 PDBIO 的保存方法: def save(self, file, select=_select, write_end=True,preserve_atom_numbering=错误): 与 Biopython 1.79 中的一样,
所以显然最大的区别是 1.80 版本中的
with fhandle:
块。
所以我意识到可以通过添加
adaptor.py
的子类来更改 StringIO
,如下所示:
from io import StringIO
class StringIO(StringIO):
def __exit__(self, *args, **kwargs):
print('exiting from subclassed StringIO !!!!!')
pass
并像这样修改
def get_structure_string(self):
:
def get_structure_string(self):
from Bio.PDB import PDBIO
#from io import StringIO
io_pdb = PDBIO()
io_pdb.set_structure(self._entity)
io_str = StringIO()
io_pdb.save(io_str)
return io_str.getvalue()
足以让我的 Biopython 1.80 在 jupiter 上使用 nglview 工作。
这告诉我不确定不关闭我们用于可视化的 StringIO 对象有什么陷阱,但显然它是 Biopython 1.79 正在做的事情,就像我使用 mmap 对象的第一个答案也在做的那样(不关闭 mmap_str)
解决问题的另一种方法:
我尝试了解Git,最终得到了这个,似乎更符合之前在biopython项目中的习惯,但无法推动它。
它利用了
as_handle
中的BIO.file
:https://github.com/biopython/biopython/blob/e1902d1cdd3aa9325b4622b25d82fbf54633e251/Bio/File.py#L28
@contextlib.contextmanager
def as_handle(handleish, mode="r", **kwargs):
r"""Context manager to ensure we are using a handle.
Context manager for arguments that can be passed to SeqIO and AlignIO read, write,
and parse methods: either file objects or path-like objects (strings, pathlib.Path
instances, or more generally, anything that can be handled by the builtin 'open'
function).
When given a path-like object, returns an open file handle to that path, with provided
mode, which will be closed when the manager exits.
All other inputs are returned, and are *not* closed.
Arguments:
- handleish - Either a file handle or path-like object (anything which can be
passed to the builtin 'open' function, such as str, bytes,
pathlib.Path, and os.DirEntry objects)
- mode - Mode to open handleish (used only if handleish is a string)
- kwargs - Further arguments to pass to open(...)
Examples
--------
>>> from Bio import File
>>> import os
>>> with File.as_handle('seqs.fasta', 'w') as fp:
... fp.write('>test\nACGT')
...
10
>>> fp.closed
True
>>> handle = open('seqs.fasta', 'w')
>>> with File.as_handle(handle) as fp:
... fp.write('>test\nACGT')
...
10
>>> fp.closed
False
>>> fp.close()
>>> os.remove("seqs.fasta") # tidy up
"""
try:
with open(handleish, mode, **kwargs) as fp:
yield fp
except TypeError:
yield handleish
有谁可以转发一下吗? [当然需要检查一下,我测试没问题,但我是新手].