def compute_salt_bridges(self): salts = [] [ self.reps.remove(index) for index, rep in reversed(list(enumerate(self.reps.replist))) ] metr = MetricDistance('sidechain and acidic and element O', 'sidechain and basic and element N', metric="contacts", threshold=3.2, pbc=False) try: data = metr.project(self) mapping = metr.getMapping(self) if len(np.shape(data)) > 1: data = data[0].copy() # handling NMR structures self.reps.add(sel='protein', style='NewCartoon', color=8) if mapping[data].atomIndexes.values.any(): for salt in mapping[data].atomIndexes.values: resid1 = self.get( "resid", sel=f"same residue as index {salt[0]}")[0] chain1 = self.get( "chain", sel=f"same residue as index {salt[0]}")[0] resid2 = self.get( "resid", sel=f"same residue as index {salt[1]}")[0] chain2 = self.get( "chain", sel=f"same residue as index {salt[1]}")[0] if [resid1, resid2] not in salts: salts.append({ "residues": [int(resid1), int(resid2)], "chain": [chain1, chain2] }) self.reps.add(f"protein and resid {resid1}", style="Licorice", color="1") self.reps.add(f"protein and resid {resid2}", style="Licorice", color="0") except: logger.error("Molecule has no basic or acidic residues") raise graph = make_graph_salts(salts) comp, _ = label_components(graph) if comp.a.size != 0: salts = add_networks_salts(graph, comp) else: logger.warning('No salt bridges present in the structure') return salts
def plot_curves(self, query: str): """ Plots the distance between the alpha carbons in the structure for the fragment region along with the number of backbone clashes of the resulting chimera for each position :param dst: np.ndarray: an array containign the distance for each fragment position :param bbContacts1: an array containing the number of bb contacts for each fragment position for the resulting chimera of combination query-subject :param bbContacts2: an array containing the number of bb contacts for each fragment position for the resulting chimera of combination subject - query :return: a matplotlib.pyplot figure. """ if self.chim_positions is None: logger.error("You need to build the chimeras before plotting. Call build_chimeras()") return dst = self.global_dst[0] residues = self.qPDB.get("resid", sel="index %s" % ' '.join(map(str, self.global_qpairs[0]))) resids = {} distances = {} for key, value in self.chim_positions.items(): if value: resids[key] = self.qPDB.get("resid", sel="index %s" % ' '.join(map(str, value))) else: resids[key] = np.zeros(0) for key, value in resids.items(): if value.any(): indices = [index for index, resi in enumerate(residues) if resi in value] distances[key] = [distance for index, distance in enumerate(dst) if index in indices] else: distances[key] = [] color = [('#FCB711', "X"), ('#CC004C', "x"), ('gray', 'o'), ('gray', "o"), ('black', ".")] colors = dict(zip(resids.keys(), color)) fig, ax = plt.subplots(figsize=(12, 9)) ax.plot(residues, dst, '-', color='black', label='distance q-s') ax.set_xlabel(f"Residue in the fragment relative to domain {query}", fontsize=24) ax.set_ylabel(r'Distance ($\AA$)', fontsize=24) i = 0 for key, value in sorted(resids.items()): if value.any(): i += 1 ax.plot(value, distances[key], colors[key][1], markersize=18, color=colors[key][0], label=key) ax.tick_params(labelsize=20) ax.tick_params(labelsize=20) ax.legend(loc=9, bbox_to_anchor=(0.5, 1.35), fontsize=18) plt.show()
def get_tmalign_output(mobile: str, target: str, matrix_filename: str) -> np.ndarray: """Reads the output matrix of TM align :param mobile: path to the query pdb file :param target: path to the subject pdb file """ try: subprocess.check_output( [TM_BIN, mobile, target, '-m', matrix_filename, '-o', "TM.sup"]) except Exception as e: logger.error(f"TMalign cannot align the molecules. Error follows {e}") matrot = [[None] * 4] * 3 with open(matrix_filename, "r") as inputfile: for i, line in enumerate(inputfile.readlines()[2:5]): matrot[i] = [float(n) for n in line.strip().split()[1:]] # os.remove(matrix_filename) return np.array(matrot)
def get_alignment(self, query: str, no: str) -> HHpredHitAlignment: """ Obtain the HHS alignment 'no' for query 'query'. Only the alignment from the fragment region is retrieved. This implies that when the fragment is not located in the N-terminus hit.q_start and the position in the output won't be the same. For example, if q_start = 20, that aminoacid is in position 0 in aln.query. :param query: str. Domain query :param no: int. Specifies the position in the file (alignment with subject) :return: HHpredHitAlignment. Alignment between query and subject for the fragment region. """ hhF = get_FUZZLE_hhs(query) try: hh = HHOutputParser().parse_file(hhF) pair = hh[int(no) - 1] aln = pair.alignment return aln except Exception as e: logger.error(f"Parsing of {hhF} failed. Error follows: {e}")
def compute_salt_bridges(self): salts = [] [ self.reps.remove(index) for index, rep in reversed(list(enumerate(self.reps.replist))) ] metr = MetricDistance('sidechain and acidic and element O', 'sidechain and basic and element N', metric="contacts", threshold=3.2, pbc=False) try: data = metr.project(self) except: logger.error("Molecule has no basic or acidic residues") raise if len(np.shape(data)) > 1: data = data[0].copy() # handling NMR structures mapping = metr.getMapping(self) self.reps.add(sel='protein', style='NewCartoon', color=8) if mapping[data].atomIndexes.values.any(): for bond in mapping[data].atomIndexes.values: resid1 = self.get("resid", sel=f"same residue as index {bond[0]}")[0] resid2 = self.get("resid", sel=f"same residue as index {bond[1]}")[0] if [resid1, resid2] not in salts: salts.append([resid1, resid2]) self.reps.add(f"protein and resid {resid1}", style="Licorice", color="1") self.reps.add(f"protein and resid {resid2}", style="Licorice", color="0") else: logger.warning("No salt bridges found in this protein") return salts
def build_chimeras(self, partial_alignment: bool = False, cutoff_distance: float = 1) -> Dict[str, Chimera]: """ Build all possible chimeras between the two proteins that fulfill these two criteria: 1) That the distance between the fusion points is below the cutoff distance 2) That the resulting chimera does not present any backbone clashes :return: A dictionary with all the possible chimeras """ if self.dst is None: logger.error("You need to align the structures before building the chimeras") chimeras = {} outcomes = ['Query N-terminal', 'Subject N-terminal', 'Not enough mutations Query N-terminal', 'Not enough mutations Subject N-terminal', 'Backbone clash'] self.chim_positions = dict(zip(outcomes, [[] for i in range(len(outcomes))])) q_indices = self.qPDB.get("index", sel="protein and name CA") qstart = min(q_indices) qend = max(q_indices) s_indices = self.sPDB.get("index", sel="protein and name CA") sstart = min(s_indices) send = max(s_indices) if partial_alignment is False: qpairs = self.global_qpairs spairs = self.global_spairs dst = self.global_dst else: qpairs = self.qpairs spairs = self.spairs dst = self.dst # Get the positions in the fragment closer than the cutoff for aln_index, chunk in enumerate(dst): if aln_index not in self.saPDB: logger.error(f"Alignment {aln_index+1} was not produced. Skipping to next alignment.") continue fusion_points = [index for index, distance in enumerate(chunk) if distance < cutoff_distance] # Build query-subject chimera for index in fusion_points: qMOL = self.qaPDB[0].copy() sMOL = self.saPDB[aln_index].copy() xo_query = qpairs[aln_index][index] xo_subject = spairs[aln_index][index] xo_index = [index for index, number in enumerate(self.global_qpairs[0]) if number == xo_query][0] residues = self.qPDB.get("resid", sel="index %s" % ' '.join(map(str, self.global_qpairs[0]))) xo_resid = residues[xo_index] try: xo_query_1 = qpairs[aln_index][index + 1] xo_subject_1 = spairs[aln_index][index + 1] except: # Position corresponds to C-terminus limit of the fragment xo_query_1 = [i + 1 for i, qindex in enumerate(q_indices) if qindex == xo_query][0] xo_subject_1 = [i + 1 for i, sindex in enumerate(s_indices) if sindex == xo_subject][0] # Combination query-subject try: chimera1, xo = self._construct_chimera(qMOL, sMOL, qstart, xo_query, xo_subject_1, send, 0) self.chim_positions['Query N-terminal'].append(xo_query) chimeras[f"comb1_{xo_resid}"] = chimera1 chimeras[f"comb1_{xo_resid}"].add_crossover(xo) except NotDiverseChimeraError: self.chim_positions['Not enough mutations Query N-terminal'].append(xo_query) except BackboneClashError: self.chim_positions['Backbone clash'].append(xo_query) # Combination subject-query try: chimera2, xo = self._construct_chimera(qMOL, sMOL, xo_query_1, qend, sstart, xo_subject, 1) self.chim_positions['Subject N-terminal'].append(xo_query) chimeras[f"comb2_{xo_resid}"] = chimera2 chimeras[f"comb2_{xo_resid}"].add_crossover(xo) except NotDiverseChimeraError: self.chim_positions['Not enough mutations Subject N-terminal'].append(xo_query) except BackboneClashError: self.chim_positions['Backbone clash'].append(xo_query) if not chimeras: logger.warning("No combination of query and subject produced a chimera that matched the criteria") return chimeras