PSP - 计算蛋白质复合物链间接触的残基与面积

news2024/11/25 14:25:35

欢迎关注我的CSDN:https://spike.blog.csdn.net/
本文地址:https://spike.blog.csdn.net/article/details/134884889

在蛋白质复合物中,通过链间距离,可以计算出在接触面的残基与接触面的面积,使用 BioPython 库 与 SASA (Solvent Accessible Surface Area,溶剂可及表面积) 库。SASA 计算主要以 水分子 是否通过为基础,水分子的半径是1.4 A,直径是 2.8 A,所以以 2.8 A 的距离,判断链间是否连接。

相关函数:

  1. 获取 蛋白质复合物 的链列表,即 get_chain_ids()
  2. 获取 残基-原子 字典,注意原子名称与 PDB 的名称可能不同,即 get_atom_list()
  3. 获取 全原子 列表,即 get_all_atoms()
  4. 判断是否原子之间是否相连,即 is_contact()
  5. 获取全部的接触面,原子计算残基维度,即 get_contacts()
  6. 打印 ChimeraX 的显示命令,即 get_chimerax_cmd()
  7. 端到端的计算接触残基,即 cal_chain_interface_residue()
  8. 计算 SASA 面积,即 cal_sasa()
  9. 获取复合物多链的子结构,即 get_sub_structure()
  10. 端到端的计算接触面积,即 cal_chain_interface_area()

以 PDB 8j18 为例,计算链 A 与 链 R 的接触残基与面积:

AR

源码如下:

#!/usr/bin/env python
# -- coding: utf-8 --
"""
Copyright (c) 2022. All rights reserved.
Created by C. L. Wang on 2023/12/8
"""

import os

from Bio.PDB import NeighborSearch
from Bio.PDB import PDBParser, Selection
from Bio.PDB.Chain import Chain
from Bio.PDB.Model import Model
from Bio.PDB.Structure import Structure

from root_dir import DATA_DIR


class MainComplexChainDist(object):
    """
    复合物,多链距离计算
    """
    def __init__(self):
        pass

    @staticmethod
    def get_chain_ids(structure):
        chain_ids = []
        for chain in structure.get_chains():
            chain_ids.append(chain.id)
        return chain_ids

    @staticmethod
    def get_atom_list(structure, chains):
        """
        获取 atom list 列表
        注意: 输出的 atom 名字与 PDB 文件中的 atom 名字略有差异,例如
        8jtl 第1个,PRO: CG 对应 OG1,CD 对应 CG2
        8jtl 第2个,VAL: CG1 对应 CD1,CG2 对应 CD2
        """
        output = dict()
        for chain in structure:
            if chain.id in chains:
                for residue in chain.get_residues():
                    het_flag, res_seq, i_code = residue.get_id()
                    the_id = (chain.id + "_" + str(res_seq) + "_" + i_code).strip()
                    for atom in residue.get_unpacked_list():
                        if het_flag == ' ':
                            if the_id in output:
                                output[the_id].append(atom)
                            else:
                                output[the_id] = [atom]
        return output

    # Filter out all the atoms from the chain,residue map given by residue_map
    @staticmethod
    def get_all_atoms(residue_map):
        all_atoms_out = []
        for residue in residue_map:
            for atom in residue_map[residue]:
                all_atoms_out.append(atom)
                # Set the b-factor to zero for coloring by contacts
                atom.set_bfactor(0.0)
        return all_atoms_out

    @staticmethod
    def is_contact(res_1, other_atoms, cutoff):
        for atom in res_1:
            ns = NeighborSearch(other_atoms)
            center = atom.get_coord()
            neighbors = ns.search(center, cutoff)  # 5.0 for distance in angstrom
            residue_list = Selection.unfold_entities(neighbors, 'R')  # R for residues
            if len(residue_list) > 0:
                return True
        return False

    @classmethod
    def get_contacts(cls, struc, all_atoms, verbose, cutoff):
        progress = 0
        contacts = []
        for residue in struc:
            progress += 1
            # if len(verbose) > 0:
            #     print(verbose, progress, "out of", len(struc))
            atom_list = struc[residue]
            outcome = cls.is_contact(atom_list, all_atoms, cutoff)
            if outcome:
                contacts.append(residue)
        return contacts

    @staticmethod
    def get_chimerax_cmd(contacts, chain_id, pdb_id="2"):
        """
        计算命令
        """
        tmp_list = []
        for item in contacts:
            req_id = int(item.split("_")[1])
            tmp_list.append(req_id)
        contacts_gap = []
        prev, post = -1, -1
        for i in tmp_list:
            if prev == -1:
                prev = post = i
                continue
            if i - post == 1:
                post = i
            else:
                contacts_gap.append(f"#{pdb_id}/{chain_id}:{prev}-{post}")
                prev = post = i
        cmd = "select " + " ".join(contacts_gap)
        return cmd

    @classmethod
    def cal_chain_interface_residue(cls, structure, chain1, chain2, cutoff=7.5):
        """
        计算复合物结构的链内距离
        """

        chain_ids = cls.get_chain_ids(structure)
        # ['A', 'B', 'G', 'R', 'S']
        print(f"[Info] chain_ids: {chain_ids}")
        assert chain1 in chain_ids and chain2 in chain_ids

        # C 表示 chain,即将 structure 展开 chain 的形式
        # 同时支持 A, R, C, M, S
        structure_c = Selection.unfold_entities(structure, target_level="C")
        atom_dict1 = cls.get_atom_list(structure_c, chains=[chain1])
        atom_dict2 = cls.get_atom_list(structure_c, chains=[chain2])
        print(f"[Info] res_num: {len(atom_dict1.keys())}")

        all_atoms_1 = cls.get_all_atoms(atom_dict1)
        all_atoms_2 = cls.get_all_atoms(atom_dict2)
        cutoff = cutoff
        contacts_1 = cls.get_contacts(atom_dict1, all_atoms_2, "First molecule, residue ", cutoff)
        contacts_2 = cls.get_contacts(atom_dict2, all_atoms_1, "Second molecule, residue ", cutoff)
        print(f"[Info] contacts_1: {len(contacts_1)}")
        print(f"[Info] contacts_2: {len(contacts_2)}")
        return contacts_1, contacts_2

    @staticmethod
    def cal_sasa(structure):
        """
        计算单体的表面积
        """
        import freesasa
        structure = freesasa.structureFromBioPDB(structure)
        result = freesasa.calc(structure)
        # classArea = freesasa.classifyResults(result, structure)
        return result.totalArea()

    @staticmethod
    def get_sub_structure(structure, chain_list):
        """
        获取 PDB 结构的子结构
        """
        new_structure = Structure(0)
        new_model = Model(0)
        # 遍历模型中的所有链
        for chain in structure[0]:
            # 获取链的ID
            tmp_chain_id = chain.get_id()
            if tmp_chain_id not in chain_list:
                continue
            # 创建一个新的结构对象,只包含当前链

            new_chain = Chain(tmp_chain_id)
            new_chain.child_list = chain.child_list
            new_model.add(new_chain)
        new_structure.add(new_model)
        return new_structure

    @classmethod
    def cal_chain_interface_area(cls, structure, chain1, chain2):
        sub_all_structure = cls.get_sub_structure(structure, [chain1, chain2])
        sub1_structure = cls.get_sub_structure(structure, [chain1])
        sub2_structure = cls.get_sub_structure(structure, [chain2])
        v1_area = cls.cal_sasa(sub_all_structure)
        v2_area = cls.cal_sasa(sub1_structure) + cls.cal_sasa(sub2_structure)
        inter_area = max(int((v2_area - v1_area) // 2), 0)
        return inter_area

    def process(self, input_path, chain1, chain2):
        """
        核心逻辑
        """
        print(f"[Info] input_path: {input_path}")
        print(f"[Info] chain1: {chain1}, chain2: {chain2}")
        chain1 = chain1.upper()
        chain2 = chain2.upper()
        parser = PDBParser(QUIET=True)
        structure = parser.get_structure("def", input_path)
        contacts_1, contacts_2 = self.cal_chain_interface_residue(structure, chain1, chain2, cutoff=7.5)
        cmd1 = self.get_chimerax_cmd(contacts_1, chain1)
        cmd2 = self.get_chimerax_cmd(contacts_2, chain2)
        print(f"[Info] chimerax: {cmd1}")
        print(f"[Info] chimerax: {cmd2}")
        inter_area = self.cal_chain_interface_area(structure, chain1, chain2)
        print(f"[Info] inter_area: {inter_area}")


def main():
    ccd = MainComplexChainDist()

    # input_path = os.path.join(DATA_DIR, "templates", "8p3l.pdb")
    # ccd.process(input_path, "A", "D")  # 2562
    # ccd.process(input_path, "A", "J")  # 490

    input_path = os.path.join(DATA_DIR, "templates", "8j18.pdb")
    # ccd.process(input_path, "R", "S")  # 0
    ccd.process(input_path, "A", "R")  # 1114


if __name__ == '__main__':
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1296815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Pytorch中使用Tensorboard可视化训练过程

这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 本节课我们来讲一下如何在pytouch当中去使用我们的tensorboard 对我们的训练过程进行一个可视化 左边有一个visualizing models data and training with tensorboard 主要是这么一个教程 那么这里…

28BYJ-48步进电机的驱动

ULN2003的工作原理 28BYJ48可以用ULN2003来驱动,STM32使用开漏模式外接5V上拉电阻也可以产生5V电压,为什么不直接使用单片机的 GPIO来驱动的原因是虽然电压符合电机的驱动要求,但单片机引脚产生的驱动电流太小,因此驱动步进电机要…

IBM Qiskit量子机器学习速成(四)

量子核机器学习 一般步骤 量子核机器学习的一般步骤如下 定义量子核 我们使用FidelityQuantumKernel类创建量子核,该类需要传入两个参数:特征映射和忠诚度(fidelity)。如果我们不传入忠诚度,该类会自动创建一个忠诚度。 注意各个类所属的…

leaflet:经纬度坐标转为地址,点击鼠标显示地址信息(137)

第137个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中将经纬度坐标转化为地址,点击鼠标显示某地的地址信息 。主要利用mapbox的api将坐标转化为地址,然后在固定的位置显示出来。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果 文章目录 示…

UniDBGrid序号列添加标题

有人想要在UniDBGrid的序号列加上标题,就是这里 可以使用如下代码 UniSession.AddJS(MainForm.UniDBGrid1.columnManager.columns[0].setText("序号"));

VMware安装Ubuntu20.04并使用Xshell连接虚拟机

文章目录 虚拟机环境准备重置虚拟网络适配器属性(可选)配置NAT模式的静态IP创建虚拟机虚拟机安装配置 Xshell连接虚拟机 虚拟机环境准备 VMware WorkStation Pro 17.5:https://customerconnect.vmware.com/cn/downloads/details?downloadGr…

样本数量对问卷信度效度分析的影响及应对策略

问卷调研是一种常见的数据收集方法。明确问卷的真实性和效率是保证其靠谱性和有效性的重要一步。但问卷的真实性和品质会受到样本数量的影响吗? 一、问卷信度的认识 1、信度的概念和重要性:在问卷实验中,信度是指问卷测量值的稳定性和一致性。高信度代…

go grpc高级用法

文章目录 错误处理常规用法进阶用法原理 多路复用元数据负载均衡压缩数据 错误处理 gRPC 一般不在 message 中定义错误。毕竟每个 gRPC 服务本身就带一个 error 的返回值,这是用来传输错误的专用通道。gRPC 中所有的错误返回都应该是 nil 或者 由 status.Status 产…

希尔排序详解:一种高效的排序方法

在探索排序算法的世界中,我们经常遇到需要对大量数据进行排序的情况。传统的插入排序虽然简单,但在处理大规模数据时效率并不高。这时,希尔排序(Shell Sort)就显得尤为重要。本文将通过深入解析希尔排序的逻辑&#xf…

分享十几个适合新手练习的软件测试项目

说实话,在找项目的过程中,我下载过(甚至付费下载过)N多个项目、联系过很多项目的作者,但是绝大部分项目,在我看来,并不适合你拿来练习,它们或多或少都存在着“问题”,比如…

编写一个程序, 给出两个时间,计算出两个时间之差,如给出1120表示11:20,1330表示13:30, 将时间间隔以分钟为单位输出。

如下: #include<stdio.h>int main(){int a,b;printf("请输入第一个时间a:");scanf("%d",&a);printf("请输入第二个时间b:");scanf("%d",&b);int hour1a/100;//取小时int minute1a%100;//取分钟int hour2b/100;int minu…

HCIP --- BGP 基础 (中)

BGP的数据包 Open、Update、Notification、Keepalive、Route-refresh BGP的公共头部 Marker &#xff1a;标记 &#xff08;可以兼容字段、版本&#xff09; 全F Length&#xff1a; 标明数据包多长多大 Type&#xff1a;表明数据包类型&#xff08;可选 12345&#xff09; …

如何切换用户和更改用户密码

https://blog.csdn.net/u012759006/article/details/89681615 https://blog.csdn.net/Z_CAIGOU/article/details/120925716 1、sudo su 切换到root用户 2、passwd 用户名 之后输入你修改后的密码两次&#xff0c;成功。 文章知识点与官方知识档案匹配&#xff0c;可 一般情…

C语言 扫雷游戏

代码在一个项目里完成&#xff0c;分成三个.c.h文件(game.c,game.h,main.c) 在Clion软件中通过运行调试。 /大概想法/ 主函数main.c里是大框架(菜单,扫雷棋盘初始化&#xff0c;随机函数生成雷&#xff0c;玩家扫雷) game.h函数声明(除main函数和游戏函数外的一些函数声明) ga…

Kafka安全性探究:构建可信赖的分布式消息系统

在本文中&#xff0c;将研究Kafka的安全性&#xff0c;探讨如何确保数据在传输和存储过程中的完整性、机密性以及授权访问。通过详实的示例代码&#xff0c;全面讨论Kafka安全性的各个方面&#xff0c;从加密通信到访问控制&#xff0c;帮助大家构建一个可信赖的分布式消息系统…

品牌控价成本如何把控

品牌在发展&#xff0c;价格就需要持续关注&#xff0c;当出现乱价、低价、窜货时就应投入人力去治理&#xff0c;但企业生存&#xff0c;还要考虑成本&#xff0c;如何在保证控价效果的基础上&#xff0c;做到使用最低成本呢&#xff0c;这些问题除了控价本身外&#xff0c;也…

苹果IOS在Safari浏览器中将网页添加到主屏幕做伪Web App,自定义图标,启动动画,自定义名称,全屏应用pwa

在ios中我们可以使用Safari浏览自带的将网页添加到主屏幕上&#xff0c;让我们的web页面看起来像一个本地应用程序一样&#xff0c;通过桌面APP图标一打开&#xff0c;直接全屏展示&#xff0c;就像在APP中效果一样&#xff0c;完全体会不到你是在浏览器中。 1.网站添加样式 在…

去掉手机端顶部间隙

Unigui手机端打开时&#xff0c;在顶部有一条白色间隙 使用以下方法可以去除间隙 在ServerModule的customcss里添加以下代码 body{ margin:0!important; padding:0!important; }

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《考虑垃圾处理与调峰需求的可持续化城市多能源系统规划》

这个标题涵盖了城市多能源系统规划中的两个重要方面&#xff1a;垃圾处理和调峰需求&#xff0c;并强调了规划的可持续性。 考虑垃圾处理&#xff1a; 含义&#xff1a; 垃圾处理指的是城市废弃物的管理和处置。这可能涉及到废物分类、回收利用、焚烧或填埋等方法。重要性&…

使用pyftpdlib组件实现FTP文件共享

目录 一、引言 二、技术背景 三、实现逻辑 1、创建FTP服务器&#xff1a; 2、实现文件共享&#xff1a; 3、设置用户权限&#xff1a; 4、处理异常&#xff1a; 5、优化与扩展&#xff1a; 四、代码实现 五、测试与评估 测试用例&#xff1a; 评估方法&#xff1a;…