def _atoms_bonds_models(objects, full_residues = False): # Treat selecting molecular surface as selecting atoms. # Returned models list does not include atomic models atoms = objects.atoms bonds = objects.bonds pbonds = objects.pseudobonds satoms = [] models = [] from chimerax.atomic import MolecularSurface, Structure, PseudobondGroup for m in objects.models: if isinstance(m, MolecularSurface): if m.has_atom_patches(): satoms.append(m.atoms) else: models.append(m) elif not isinstance(m, (Structure, PseudobondGroup)): models.append(m) if satoms: from chimerax.atomic import concatenate atoms = concatenate([atoms] + satoms) if full_residues: if len(bonds) > 0 or len(pbonds) > 0: a1, a2 = bonds.atoms pa1, pa2 = pbonds.atoms from chimerax.atomic import concatenate atoms = concatenate([atoms, a1, a2, pa1, pa2]) atoms = atoms.unique_residues.atoms bonds = atoms.intra_bonds return atoms, bonds, pbonds, models
def atoms(self): ''' Returns an unsorted `Atoms` object encompassing all atoms in chi dihedrals. Read only. ''' from chimerax.atomic import concatenate, Atoms dihedrals = concatenate([r.chi_dihedrals for r in self]) return concatenate([Atoms(d.atoms) for d in dihedrals]).unique()
def paired_atoms(atoms, to_atoms, match_chain_ids, match_numbering, match_atom_names): # TODO: return summary string of all dropped atoms. if match_chain_ids: pat = pair_chains(atoms, to_atoms) elif match_numbering: # Pair chains in order of matching sequence numbers but not chain ids. ca, cta = atoms.by_chain, to_atoms.by_chain n = min(len(ca), len(cta)) # TODO: Warn if unequal number of sequences. pat = [(ca[i][2], cta[i][2]) for i in range(n)] else: pat = [(atoms, to_atoms)] if match_numbering: pat = sum([pair_sequence_numbers(a, ta) for a, ta in pat], []) if match_atom_names: pat = sum([pair_atom_names(a, ta) for a, ta in pat], []) for pa, pta in pat: if len(pa) != len(pta): msg = 'Unequal number of atoms to pair, %d and %d' % (len(pa), len(pta)) if match_chain_ids: msg += ', chain %s' % pa[0].chain_id if match_numbering: msg += ', residue %d' % pa[0].residue.number raise UserError(msg) from chimerax.atomic import Atoms, concatenate pas = concatenate([pa[0] for pa in pat], Atoms) ptas = concatenate([pa[1] for pa in pat], Atoms) return pas, ptas
def _hbondatoms_selector(session, models, results): from chimerax.atomic import Pseudobonds, PseudobondGroup, concatenate pbonds = concatenate([pbg.pseudobonds for pbg in models if isinstance(pbg, PseudobondGroup) and pbg.name == 'hydrogen bonds'], Pseudobonds) if len(pbonds) > 0: atoms = concatenate(pbonds.atoms) results.add_atoms(atoms) for m in atoms.unique_structures: results.add_model(m)
def atoms(self): ''' Returns an unsorted `Atoms` object encompassing all atoms in phi, psi and omega (if present). ''' from chimerax.atomic import Atoms, concatenate return concatenate([ concatenate(dihedrals.atoms) for dihedrals in [self.phi_dihedrals, self.psi_dihedrals, self.omega_dihedrals] ]).unique()
def rota(session, structures=None, report=False): ''' Add a live rotamer validator to each of the given structures, and optionally report a summary of current outliers. ''' from chimerax.isolde import session_extensions as sx if structures is None: from chimerax.atomic import AtomicStructure structures = [ m for m in session.models.list() if type(m) == AtomicStructure ] for structure in structures: sx.get_rota_annotator(structure) if report: from chimerax.atomic import Residues, concatenate residues = concatenate([m.residues for m in structures]) mgr = sx.get_rotamer_mgr(session) rotamers = mgr.get_rotamers(residues) report_str = 'NON-FAVOURED ROTAMERS: \n' nf, scores = mgr.non_favored_rotamers(rotamers) for r, score in zip(nf, scores): report_str += '#{:<6} {}:\t{} {} (P={:.4f})\n'.format( r.residue.structure.id_string, r.residue.chain_id, r.residue.name, r.residue.number, score) session.logger.info(report_str)
def assign_unbound_residues(m, chain_map, unclassified): from chimerax.atomic import Residue, concatenate for cid, residues in chain_map.items(): first_ligand_number = next_available_ligand_number(m, cid) residues.chain_ids = cid + 'tmp' residues = concatenate([ residues[residues.names != 'HOH'], residues[residues.names == 'HOH'] ]) m.renumber_residues(residues, first_ligand_number) residues.chain_ids = cid if len(unclassified): # Try reclassifying with a more permissive cutoff, now that all the other ligands # are assigned to chains chain_map, unclassified = cluster_unbound_ligands(m, unclassified, cutoff=8) assign_unbound_residues(m, chain_map, []) if len(unclassified): session = m.session warn_str = ( '{} residues could not be automatically assigned to chains. ' 'These have been given the chain ID UNK.').format( len(unclassified)) session.logger.warning(warn_str) unclassified.chain_ids = 'UNK' m.renumber_residues(unclassified, 1)
def _pbonds_selector(session, models, results): from chimerax.atomic import Pseudobonds, PseudobondGroup, concatenate pbonds = concatenate([pbg.pseudobonds for pbg in models if isinstance(pbg, PseudobondGroup)], Pseudobonds) results.add_pseudobonds(pbonds) for m in pbonds.unique_groups: results.add_model(m)
def collate_results(results, return_collection): if return_collection: from chimerax.atomic import concatenate return concatenate(results) ret_val = [] for result in results: ret_val.extend(result) return ret_val
def _link_specs(links): m1,m2 = links.atoms from chimerax.atomic import concatenate markers = concatenate((m1,m2)) mlinks = markers.intra_bonds if len(mlinks) == len(links): lspecs = [_markers_spec(markers)] else: lspecs = [_markers_spec(Atoms(mpair)) for mpair in zip(m1,m2)] return lspecs
def __init__(self, structures): self.name = structures[0].name + " (combined)" from chimerax.atomic import concatenate self.atoms = concatenate([s.atoms for s in structures]) self.bonds = concatenate([s.bonds for s in structures]) self.residues = concatenate([s.residues for s in structures]) self.pbg_map = { Structure.PBG_METAL_COORDINATION: JPBGroup(self.atoms) } # if combining single-residue structures, # can be more informative to use model name # instead of residue type for substructure if len(structures) == len(self.residues): rnames = self.residues.names if len(set(rnames)) < len(rnames): snames = [s.name for s in structures] if len(set(snames)) == len(snames): self.substructure_names = dict( zip(self.residues, snames))
def extend_to_chains(atoms): '''Return atoms extended to all atoms in same chains (ie same chain id / structure).''' catoms = [] from numpy import in1d for s, a in atoms.by_structure: satoms = s.atoms catoms.append(satoms.filter(in1d(satoms.chain_ids, a.unique_chain_ids))) from chimerax.atomic import concatenate, Atoms return concatenate(catoms, Atoms)
def show_pseudobonds(session, objects, only, undo_state): pbonds = objects.pseudobonds undo_state.add(pbonds, "displays", pbonds.displays, True) pbonds.displays = True a1, a2 = pbonds.atoms undo_state.add(a1, "displays", a1.displays, True) a1.displays = True # Atoms need to be displayed for bond to appear undo_state.add(a2, "displays", a1.displays, True) a2.displays = True if only: from chimerax.atomic import concatenate atoms = concatenate([a1, a2]) pbs = sum([[pbg.pseudobonds for pbg in m.pbg_map.values()] for m in atoms.unique_structures], []) if pbs: all_pbonds = concatenate(pbs) other_pbonds = all_pbonds - pbonds undo_state.add(other_pbonds, "displays", other_pbonds.displays, False) other_pbonds.displays = False
def __init__(self, session, contact, flip=False, interface_residue_area_cutoff=15): self.contact = c = contact # Interface residues g1, g2 = (c.group2, c.group1) if flip else (c.group1, c.group2) min_area = interface_residue_area_cutoff self.residues1 = r1 = c.contact_residues(g1, min_area) self.residues2 = r2 = c.contact_residues(g2, min_area) from chimerax.atomic import concatenate self.residues = res = concatenate((r1, r2)) # Non-interface residues self.atoms1, self.atoms2 = a1, a2 = g1.atoms, g2.atoms self.noninterface_residues1 = a1.unique_residues.subtract(r1) self.noninterface_residues2 = a2.unique_residues.subtract(r2) allres = concatenate((a1, a2)).unique_residues self.noninterface_residues = allres.subtract(res) # Create matplotlib panel nodes = tuple(ResidueNode(r) for r in res) bnodes = tuple( ResidueNode(r, size=800, color=(.7, .7, .7, 1), background=True) for r in self.noninterface_residues1) edges = () title = '%s %d residues with %s %d residues' % (g2.name, len(r2), g1.name, len(r1)) Graph.__init__(self, session, nodes + bnodes, edges, "Chain Contacts", title=title) self.font_size = 8 self._interface_shown = False self.draw_graph()
def pseudobond_connections(structures): pcon = {} from chimerax.atomic import concatenate, Atoms, interatom_pseudobonds from chimerax.geometry import distance satoms = concatenate([s.atoms for s in structures], Atoms) for pb in interatom_pseudobonds(satoms): a1, a2 = pb.atoms if pb.shown and pb.group.display: d12 = distance(a1.scene_coord, a2.scene_coord) pcon.setdefault(a1, []).append((a2,d12)) pcon.setdefault(a2, []).append((a1,d12)) return pcon
def _mdff_changed_cb(self, trigger_name, changes): mgr, changes = changes change_types = list(changes.keys()) from chimerax.atomic import concatenate changeds = [] if 'enabled/disabled' in change_types: changeds.append(changes['enabled/disabled']) if 'spring constant changed' in change_types: changeds.append(changes['spring constant changed']) if len(changeds): all_changeds = concatenate(changeds, remove_duplicates=True) all_changeds = all_changeds[all_changeds.sim_indices != -1] self.sim_handler.update_mdff_atoms(all_changeds, mgr.volume)
def shortcut_atoms(session): matoms = [] sel = session.selection atoms_list = sel.items('atoms') from chimerax.atomic import concatenate, Atoms if atoms_list: atoms = concatenate(atoms_list) elif sel.empty(): # Nothing selected, so operate on all atoms from chimerax.atomic import all_atoms atoms = all_atoms(session) else: atoms = Atoms() return atoms
def process_clashes(session, residue, by_alt_loc, overlap, hbond_allow, score_method, make_pbs, pb_color, pb_radius, ignore_others): if make_pbs: pbg = session.pb_manager.get_group("clashes") pbg.clear() pbg.radius = pb_radius pbg.color = pb_color.uint8x4() else: pbg = session.pb_manager.get_group("clashes", create=False) if pbg: session.models.close([pbg]) from chimerax.atomic import concatenate from chimerax.clashes import find_clashes CA = residue.find_atom("CA") alt_locs = CA.alt_locs if CA.alt_locs else [' '] res_atoms = set(residue.atoms) with CA.suppress_alt_loc_change_notifications(): for alt_loc, rots in by_alt_loc.items(): CA.alt_loc = alt_loc test_atoms = concatenate([rot.atoms for rot in rots]) clash_info = find_clashes(session, test_atoms, clash_threshold=overlap, hbond_allowance=hbond_allow) for rot in rots: score = 0 for ra in rot.atoms: if ra.name in ("CA", "N", "CB"): # any clashes of CA/N/CB are already clashes of base residue (and may # mistakenly be thought to clash with "bonded" atoms in nearby residues) continue if ra not in clash_info: continue for ca, clash in clash_info[ra].items(): if ca in res_atoms: continue if ignore_others and ca.structure != residue.structure: continue if score_method == "num": score += 1 else: score += clash if make_pbs: pbg.new_pseudobond(ra, ca) rot.clash_score = score if score_method == "num": return "%2d" return "%4.2f"
def cmd_centroid(session, atoms=None, *, mass_weighting=False, name="centroid", color=None, radius=2.0): """Wrapper to be called by command line. Use chimerax.centroids.centroid for other programming applications. """ from chimerax.core.errors import UserError from chimerax.atomic import AtomicStructure, concatenate, Structure if atoms is None: structures_atoms = [m.atoms for m in session.models if isinstance(m, AtomicStructure)] if structures_atoms: atoms = concatenate(structures_atoms) else: raise UserError("Atom specifier selects no atoms") structures = atoms.unique_structures if len(structures) > 1: crds = atoms.scene_coords else: crds = atoms.coords if mass_weighting: masses = atoms.elements.masses avg_mass = masses.sum() / len(masses) import numpy weights = masses[:, numpy.newaxis] / avg_mass else: weights = None xyz = centroid(crds, weights=weights) s = Structure(session, name=name) r = s.new_residue('centroid', 'centroid', 1) from chimerax.atomic.struct_edit import add_atom a = add_atom('cent', 'C', r, xyz) if color: a.color = color.uint8x4() else: from chimerax.atomic.colors import element_color, predominant_color color = predominant_color(atoms) if color is None: a.color = element_color(a.element.number) else: a.color = color a.radius = radius if len(structures) > 1: session.models.add([s]) else: structures[0].add([s]) session.logger.info("Centroid '%s' placed at %s" % (name, xyz)) return a
def info_selection(session, level=None, attribute=None): if level is None or level == "atom": if attribute is None: attribute = "idatm_type" atoms = session.selection.items("atoms") if atoms: from chimerax.atomic import concatenate report_atoms(session.logger, concatenate(atoms), attribute) elif level == "residue": if attribute is None: attribute = "name" atoms = session.selection.items("atoms") if atoms: from chimerax.atomic import concatenate residues = concatenate([a.unique_residues for a in atoms]) report_residues(session.logger, residues, attribute) elif level == "chain": if attribute is None: attribute = "chain_id" atoms = session.selection.items("atoms") if atoms: from chimerax.atomic import concatenate chains = concatenate([a.residues.unique_chains for a in atoms]) report_chains(session.logger, chains, attribute) elif level == "structure": if attribute is None: attribute = "name" atoms = session.selection.items("atoms") if atoms: from chimerax.atomic import concatenate mols = concatenate([a.unique_structures for a in atoms]) report_models(session.logger, mols, attribute) elif level == "model": if attribute is None: attribute = "name" report_models(session.logger, session.selection.models(), attribute)
def _surface_atoms(session, objects): if objects is None: from chimerax.atomic import all_atoms atoms = all_atoms(session) else: atoms = objects.atoms from chimerax.atomic import MolecularSurface satoms = [ s.atoms for s in objects.models if isinstance(s, MolecularSurface) ] if satoms: from chimerax.atomic import concatenate, Atoms atoms = concatenate([atoms] + satoms, Atoms, remove_duplicates=True) return atoms
def _pr_changed_cb(self, trigger_name, changes): mgr, changes = changes change_types = list(changes.keys()) from chimerax.atomic import concatenate changeds = [] if 'target changed' in change_types: changeds.append(changes['target changed']) if 'enabled/disabled' in change_types: changeds.append(changes['enabled/disabled']) if 'spring constant changed' in change_types: changeds.append(changes['spring constant changed']) if len(changeds): all_changeds = concatenate(changeds, remove_duplicates=True) # limit to restraints that are actually in the simulation # TODO: might be better to just ignore -1 indices in the update_... functions all_changeds = all_changeds[all_changeds.sim_indices != -1] self.sim_handler.update_position_restraints(all_changeds)
def show_bonds(session, objects, only, undo_state): bonds = objects.bonds undo_state.add(bonds, "displays", bonds.displays, True) bonds.displays = True a1, a2 = bonds.atoms undo_state.add(a1, "displays", a1.displays, True) a1.displays = True # Atoms need to be displayed for bond to appear undo_state.add(a2, "displays", a2.displays, True) a2.displays = True if only: mbonds = [m.bonds for m in atoms.unique_structures] if mbonds: from chimerax.atomic import concatenate all_bonds = concatenate(mbonds) other_bonds = all_bonds - bonds undo_state.add(other_bonds, "displays", other_bonds.displays, False) other_bonds.displays = False
def _show_contact_residues(self, g, color=(180, 180, 180, 255)): from .cmd import neighbors ng = neighbors(g, self.contacts) # Map neighbor node to Contact min_area = self.interface_residue_area_cutoff gca = [] for h in self.groups: if h in ng: c = ng[h] atoms = c.contact_residue_atoms(h, min_area) h.show(False) atoms.displays = True # Show only contacting residues atoms.draw_modes = atoms.STICK_STYLE gatoms = c.contact_residue_atoms(g, min_area) # gatoms.draw_modes = gatoms.STICK_STYLE gca.append(gatoms) else: h.show(h is g) # Color non-contact atoms gray. from chimerax.atomic import concatenate, Atoms g.color_atoms(g.atoms - concatenate(gca, Atoms), color)
def get_protein_backbone_problems(structure, outliers_only=True): from chimerax.isolde import session_extensions as sx rmgr = sx.get_ramachandran_mgr(structure.session) residues = structure.residues if outliers_only: f = rmgr.outliers else: f = rmgr.non_favored problems = f(residues) # Also count twisted and cis-nonPro peptide bonds here cis = rmgr.cis(residues) cis_nonpro = cis[cis.names != 'PRO'] # Note: this will probably lead to double-counting since # twisted peptides will usually also be captured by # get_torsion_restraint_problems()... but ultimately I # don't think that's a huge problem. twisted = rmgr.twisted(residues) from chimerax.atomic import concatenate, Residues twisted = Residues([t[0] for t in twisted]) problems = concatenate([problems, cis_nonpro, twisted]) problem_ramas = rmgr.get_ramas(problems) return problem_ramas
def split_atoms(atoms, asubsets): # Eliminate subset atoms not in atoms asubsets = [asub.intersect(atoms) for asub in asubsets] # Remove empty subsets asubsets = [asub for asub in asubsets if len(asub) > 0] # Find atoms not in any subset from chimerax.atomic import concatenate, Atoms a0 = atoms.subtract(concatenate(asubsets, Atoms)) # Return groups of atoms if len(a0) == len(atoms): pieces = [('',atoms)] elif len(a0) == 0 and len(asubsets) == 1: pieces = [('',atoms)] else: alists = (asubsets + [a0]) if len(a0) > 0 else asubsets pieces = [(str(i+1),a) for i,a in enumerate(alists)] return pieces
def rama(session, structures=None, show_favored=True, report=False): ''' Add a live Ramachandran validator to each of the given structures, and optionally report a summary of current outliers and cis/twisted peptide bonds. ''' from chimerax.isolde import session_extensions as sx if structures is None: from chimerax.atomic import AtomicStructure structures = [ m for m in session.models.list() if type(m) == AtomicStructure ] for structure in structures: ra = sx.get_RamaAnnotator(structure) ra.hide_favored = not show_favored if report: from chimerax.atomic import Residues, concatenate residues = concatenate([m.residues for m in structures]) mgr = sx.get_ramachandran_mgr(session) report_str = 'RAMACHANDRAN OUTLIERS: \n' outliers = mgr.outliers(residues) for outlier in outliers: report_str += '#{:<6} {}:\t{} {}\n'.format( outlier.structure.id_string, outlier.chain_id, outlier.name, outlier.number) report_str += '\nCIS PEPTIDE BONDS: \n' cispeps = mgr.cis(residues) for cis in cispeps: report_str += '#{:<6} {}:\t{} {}\n'.format(cis.structure.id_string, cis.chain_id, cis.name, cis.number) report_str += '\nTWISTED PEPTIDE BONDS: \n' twisteds = mgr.twisted(residues) for twisted, angle in twisteds: report_str += '#{:<6} {}:\t{} {} ({:.1f}°)\n'.format( twisted.structure.id_string, twisted.chain_id, twisted.name, twisted.number, angle) session.logger.info(report_str)
def move_atoms(atoms, to_atoms, tf, move): if move == 'structures' or move is True: for m in atoms.unique_structures: m.scene_position = tf * m.scene_position else: from chimerax.atomic import Atoms if move == 'atoms': matoms = atoms elif move == 'residues': matoms = atoms.unique_residues.atoms elif move == 'chains': matoms = extend_to_chains(atoms) elif move == 'structure atoms': from chimerax.atomic import concatenate, Atoms matoms = concatenate([m.atoms for m in atoms.unique_structures], Atoms) elif isinstance(move, Atoms): matoms = move else: return # Move nothing matoms.scene_coords = tf * matoms.scene_coords
def show_surfaces(session, objects, only, undo_state): # TODO: fill in undo data atoms = objects.atoms if len(atoms) == 0: return # Show existing surfaces from chimerax.atomic import molsurf, concatenate, Atoms surfs = molsurf.show_surface_atom_patches(atoms, only=only) # Create new surfaces if they don't yet exist. if surfs: patoms, all_small = molsurf.remove_solvent_ligands_ions(atoms) extra_atoms = patoms - concatenate([s.atoms for s in surfs], Atoms) if extra_atoms: # Handle case where atoms were added to existing surfaces # so those surfaces will be replaced. Bug #2603. extra_atoms = atoms else: extra_atoms = atoms if extra_atoms: from chimerax.surface import surface surface(session, extra_atoms)
def assign_bound_ligand_chain_ids_and_residue_numbers(m, bound_map): # The wwPDB steering committee has dictated that for protein-linked glycans, # the following rules apply: # - if the modelled portion of the glycan is a single residue, it should have # the same chain ID as the protein. # - if more than one residue, it should have a unique chain ID. from chimerax.atomic import Residues, Residue, concatenate import numpy for cid, bound_residues in bound_map.items(): first_ligand_number = next_available_ligand_number(m, cid) new_glycan_cid = [] assign_to_chain = [] groups = independent_groupings(bound_residues) for g in groups: if len(g) == 1: assign_to_chain.append(g) elif any(r.name in known_sugars for r in g): new_glycan_cid.append(g) else: assign_to_chain.append(g) new_glycan_cid = list( sorted(new_glycan_cid, key=lambda g: linked_polymer_residue(g).number)) assign_to_chain = list( sorted(assign_to_chain, key=lambda g: linked_polymer_residue(g).number)) for i, g in enumerate(new_glycan_cid): gid = cid + 'gl' + str(i) residues = sort_glycan_residues(g) residues.chain_ids = gid m.renumber_residues(residues, 1) if len(assign_to_chain): assign_to_chain = concatenate( [Residues(g) for g in assign_to_chain]) assign_to_chain.chain_ids = 'XXtmp' m.renumber_residues(assign_to_chain, first_ligand_number) assign_to_chain.chain_ids = cid