使用 nglview.show_biopython(struct) 时出现文件 I/O 错误

问题描述 投票:0回答:3

所以我一直在尝试用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() 函数无法正常工作。

python jupyter-notebook anaconda bioinformatics biopython
3个回答
3
投票

我还想出了另一种方法来解决这个问题。回到我正在谈论的教程后,我看到它是在 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


2
投票

我也遇到过类似的问题:

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)


0
投票

解决问题的另一种方法:

我尝试了解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

有谁可以转发一下吗? [当然需要检查一下,我测试没问题,但我是新手].

© www.soinside.com 2019 - 2024. All rights reserved.