| """ |
| 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): |
| |
| 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) |
|
|