wuxing0105's picture
Upload folder using huggingface_hub
80a72c3 verified
Raw
History Blame Contribute Delete
4.71 kB
"""
Utilties for converting to/from a dictionary representation of domain assignments.
"""
import logging
import os
from itertools import product
import numpy as np
import warnings
from Bio.PDB.PDBExceptions import PDBConstructionWarning
warnings.simplefilter('ignore', PDBConstructionWarning)
LOG = logging.getLogger(__name__)
def make_pair_labels(n_res, domain_dict, id_string=None, save_dir=None, non_aligned_residues=[]):
"""n_res: number of residues in the non-trimmed sequence
non_aligned_residues: these will be used to trim down from n_res
domain_dict: eg. {'D1': [0,1,2,3], 'D2': [4,5,6]}
"""
pair_labels = np.zeros([n_res, n_res])
for domain, res_ix in domain_dict.items():
if domain == 'linker':
continue
coords_tuples = list(product(res_ix, res_ix))
x_ix = [i[0] for i in coords_tuples]
y_ix = [i[1] for i in coords_tuples]
pair_labels[x_ix, y_ix] = 1
if len(non_aligned_residues):
aligned_residues = [i for i in range(n_res) if i not in non_aligned_residues]
pair_labels = pair_labels[aligned_residues,:][:,aligned_residues]
if save_dir is not None:
save_path = os.path.join(save_dir, id_string)
np.savez_compressed(save_path, pair_labels)
return pair_labels
def sort_domain_limits(limits, dom_names):
start_positions = [x[0] for x in limits]
end_positions = [x[1] for x in limits]
sorted_index = np.argsort(start_positions)
assert (sorted_index == np.argsort(end_positions)).all()
return np.array(limits)[sorted_index], list(np.array(dom_names)[sorted_index])
def resolve_residue_in_multiple_domain(mapping, shared_res):
"""
This is a stupid slow recursive solution: but I think it only applies to one
case so going to leave it for now
"""
for one_shared in shared_res:
for domain, res in mapping.items():
if one_shared in res:
mapping[domain].remove(one_shared)
return check_no_residue_in_multiple_domains(mapping)
def check_no_residue_in_multiple_domains(mapping, resolve_conflics=True):
# ensures no residue index is associated with more than one domain
for dom, res in mapping.items():
for dom2, res2 in mapping.items():
if dom == dom2:
continue
shared_res = set(res).intersection(set(res2))
if len(shared_res):
print(f'Found {len(shared_res)} shared residues')
if resolve_conflics:
mapping = resolve_residue_in_multiple_domain(mapping, shared_res)
else:
raise ValueError("SAME RESIDUE NUMBER FOUND IN MULTIPLE DOMAINS")
return mapping
def make_domain_mapping_dict(row):
dom_limit_list = row.dom_bounds_pdb_ix.split('|')
dom_names = row.dom_names.split('|')
dom_limit_list = convert_limits_to_numbers(dom_limit_list)
dom_limit_array, dom_names = sort_domain_limits(dom_limit_list, dom_names)
mapping = {}
for i, d_lims in enumerate(dom_limit_array):
dom_name = dom_names[i]
pdb_start, pdb_end = d_lims
if dom_name not in mapping:
mapping[dom_name] = []
mapping[dom_name] += list(range(pdb_start, pdb_end))
check_no_residue_in_multiple_domains(mapping)
return mapping
def convert_limits_to_numbers(dom_limit_list):
processed_dom_limit_list = []
for lim in dom_limit_list:
dash_idx = [i for i, char in enumerate(lim) if char == '-']
if len(dash_idx) == 1:
start_index = int(lim.split('-')[0]) -1
end_index = int(lim.split('-')[1])
else:
raise ValueError('Invalid format for domain limits', str(dom_limit_list))
processed_dom_limit_list.append((start_index, end_index))
return processed_dom_limit_list
def convert_domain_dict_strings(domain_dict):
"""
Converts the domain dictionary into domain_name string and domain_bounds string
eg. domain names D1|D2|D1
eg. domain bounds 0-100|100-200|200-300
"""
domain_names = []
domain_bounds = []
for k,v in domain_dict.items():
if k=='linker':
continue
residues = sorted(v)
for i, res in enumerate(residues):
if i==0:
start = res
elif residues[i-1] != res - 1:
domain_bounds.append(f'{start}-{residues[i-1]}')
domain_names.append(k)
start = res
if i == len(residues)-1:
domain_bounds.append(f'{start}-{res}')
domain_names.append(k)
return '|'.join(domain_names), '|'.join(domain_bounds)