def _undo_save(self): if self._moved: if self._moving_atoms: if self._starting_atom_scene_coords is not None: from chimerax.core.undo import UndoState undo_state = UndoState('move atoms') a = self._atoms undo_state.add(a, "scene_coords", self._starting_atom_scene_coords, a.scene_coords) self.session.undo.register(undo_state) elif self._starting_model_positions is not None: from chimerax.core.undo import UndoState undo_state = UndoState('move models') models = self.models() new_model_positions = [m.position for m in models] undo_state.add(models, "position", self._starting_model_positions, new_model_positions, option='S') self.session.undo.register(undo_state) self._starting_atom_scene_coords = None self._starting_model_positions = None
def select_intersect(session, objects=None, residues=False): '''Reduce the selection by intersecting with specified objects.''' from chimerax.core.undo import UndoState undo_state = UndoState("select intersect") intersect_selection(objects, session, undo_state, full_residues = residues) session.undo.register(undo_state) report_selection(session)
def select_pick(session, pick, mode='replace'): sel = session.selection from chimerax.core.undo import UndoState undo_state = UndoState("select") sel.undo_add_selected(undo_state, False) if pick is None or (isinstance(pick, list) and len(pick) == 0): if mode == 'replace': from chimerax.core.commands import run run(session, 'select clear') session.logger.status('cleared selection') else: if mode == 'replace': sel.clear() mode = 'add' if isinstance(pick, list): for p in pick: p.select(mode) if pick: session.logger.info('Drag select of %s' % _pick_description(pick)) else: spec = pick.specifier() if mode == 'add' and spec: from chimerax.core.commands import run run(session, 'select %s' % spec) else: pick.select(mode) sel.clear_promotion_history() sel.undo_add_selected(undo_state, True, old_state=False) session.undo.register(undo_state)
def select_clear(session): '''Clear the selection.''' from chimerax.core.undo import UndoState undo_state = UndoState("select clear") with session.triggers.block_trigger("selection changed"): clear_selection(session, undo_state) session.undo.register(undo_state)
def select_subtract(session, objects=None, residues=False): '''Subtract objects from the selection. If objects is None the selection is cleared.''' from chimerax.core.undo import UndoState undo_state = UndoState("select subtract") if objects is None: clear_selection(session, undo_state) else: modify_selection(objects, 'subtract', undo_state, full_residues = residues) session.undo.register(undo_state) report_selection(session)
def select_add(session, objects=None, residues=False): '''Add objects to the selection. If objects is None everything is selected.''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) from chimerax.core.undo import UndoState undo_state = UndoState("select add") modify_selection(objects, 'add', undo_state, full_residues = residues) session.undo.register(undo_state) report_selection(session)
def cartoon_tether(session, structures=None, scale=None, shape=None, sides=None, opacity=None): '''Set cartoon ribbon tether options for specified structures. Parameters ---------- structures : atomic structures Set option for selected atomic structures. scale : floating point number Scale factor relative to atom display radius. A scale factor of zero means the tether is not displayed. This parameter applies at the atomic structure level, so setting it for any residue sets it for the entire structure. shape : string Sets shape of tethers. "cone" has point on ribbon and base at atom. "steeple" has point at atom and base on ribbon. "cylinder" is bond-like. This parameter applies at the atomic structure level, so setting it for any residue sets it for the entire structure. sides : integer Number of sides for either the cylinder or cone base depending on tether shape. This parameter applies at the atomic structure level, so setting it for any residue sets it for the entire structure. opacity : floating point number Scale factor relative to atom opacity. This parameter applies at the atomic structure level, so setting it for any residue sets it for the entire structure. ''' structures = _get_structures(session, structures) if scale is None and shape is None and sides is None and opacity is None: indent = " -" for m in structures: print(m) print(indent, "scales", m.ribbon_tether_scale) print(indent, "shapes", _TetherShapeInverseMap[m.ribbon_tether_shape]) print(indent, "sides", m.ribbon_tether_sides) print(indent, "opacity", m.ribbon_tether_opacity) return from chimerax.core.undo import UndoState undo_state = UndoState("cartoon tether") if scale is not None: undo_state.add(structures, "ribbon_tether_scales", structures.ribbon_tether_scales, scale) structures.ribbon_tether_scales = scale if shape is not None: ts = _TetherShapeMap.get(shape, Structure.TETHER_CONE) undo_state.add(structures, "ribbon_tether_shapes", structures.ribbon_tether_shapes, ts) structures.ribbon_tether_shapes = ts if sides is not None: undo_state.add(structures, "ribbon_tether_sides", structures.ribbon_tether_sides, sides) structures.ribbon_tether_sides = sides if opacity is not None: undo_state.add(structures, "ribbon_tether_opacities", structures.ribbon_tether_opacities, opacity) structures.ribbon_tether_opacities = opacity session.undo.register(undo_state)
def _color_by_map_value(session, surfaces, map, palette = None, range = None, offset = 0, transparency = None, gradient = False, caps_only = False, auto_update = True, undo_name = 'color map by value'): surfs = [s for s in surfaces if s.vertices is not None] cs_class = GradientColor if gradient else VolumeColor from chimerax.core.undo import UndoState undo_state = UndoState(undo_name) for surf in surfs: cprev = surf.color_undo_state cs = cs_class(surf, map, palette, range, transparency = transparency, offset = offset, auto_recolor = auto_update) cs.set_vertex_colors() undo_state.add(surf, 'color_undo_state', cprev, surf.color_undo_state) session.undo.register(undo_state)
def hide(session, objects=None, what=None, target=None): '''Hide specified atoms, bonds or models. Parameters ---------- objects : Objects or None Atoms, bonds or models to hide. If None then all are hidden. what : 'atoms', 'bonds', 'pseudobonds', 'pbonds', 'cartoons', 'ribbons', 'models' or None What to hide. If None then 'atoms' if any atoms specified otherwise 'models'. target : set of "what" values, or None Alternative to the "what" option for specifying what to hide. ''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) from .show import what_objects what_to_hide = what_objects(target, what, objects) from chimerax.core.undo import UndoState undo_state = UndoState("hide") if 'atoms' in what_to_hide: atoms = objects.atoms undo_state.add(atoms, "displays", atoms.displays, False) atoms.displays = False atoms.update_ribbon_backbone_atom_visibility() if 'bonds' in what_to_hide: bonds = objects.bonds undo_state.add(bonds, "displays", bonds.displays, False) bonds.displays = False if 'pseudobonds' in what_to_hide or 'pbonds' in what_to_hide: from chimerax import atomic pbonds = objects.pseudobonds undo_state.add(pbonds, "displays", pbonds.displays, False) pbonds.displays = False if 'cartoons' in what_to_hide or 'ribbons' in what_to_hide: res = objects.residues undo_state.add(res, "ribbon_displays", res.ribbon_displays, False) res.ribbon_displays = False if 'surfaces' in what_to_hide: from chimerax.atomic import molsurf # TODO: save undo data molsurf.hide_surface_atom_patches(objects.atoms) if 'models' in what_to_hide: hide_models(objects, undo_state) session.undo.register(undo_state)
def cartoon(session, atoms=None, smooth=None, suppress_backbone_display=None, spine=False): '''Display cartoon for specified residues. Parameters ---------- atoms : Atoms Show ribbons for the specified residues. If no atom specifier is given then ribbons are shown for all residues. Residues that are already shown as ribbons remain shown as ribbons. smooth : floating point number Adjustment factor for strand and helix smoothing. A factor of zero means the cartoon will pass through the atom position. A factor of one means the cartoon will pass through the "ideal" position, e.g., center of the cylinder that best fits a helix. A factor of "default" means to return to default (0.7 for strands and 0 for everything else). suppress_backbone_display : boolean Set whether displaying a ribbon hides the sphere/ball/stick representation of backbone atoms. spine : boolean Display ribbon "spine" (horizontal lines across center of ribbon). This parameter applies at the atomic structure level, so setting it for any residue sets it for the entire structure. ''' if atoms is None: from chimerax.atomic import all_residues residues = all_residues(session) else: residues = atoms.unique_residues from chimerax.core.undo import UndoState undo_state = UndoState("cartoon") undo_state.add(residues, "ribbon_displays", residues.ribbon_displays, True) residues.ribbon_displays = True if smooth is not None: if smooth is "default": # Convert to C++ default value smooth = -1.0 undo_state.add(residues, "ribbon_adjusts", residues.ribbon_adjusts, smooth) residues.ribbon_adjusts = smooth if suppress_backbone_display is not None: undo_state.add(residues, "ribbon_hide_backbones", residues.ribbon_hide_backbones, suppress_backbone_display) residues.ribbon_hide_backbones = suppress_backbone_display if spine is not None: structures = residues.unique_structures undo_state.add(structures, "ribbon_show_spines", structures.ribbon_show_spines, spine) structures.ribbon_show_spines = spine session.undo.register(undo_state)
def _color_geometry(session, surfaces, geometry='radial', center=None, axis=None, coordinate_system=None, palette='redblue', range=None, auto_update=True, caps_only=False): surfs = [s for s in surfaces if s.vertices is not None] c0 = None if center: c0 = center.scene_coordinates(coordinate_system) elif axis: c0 = axis.base_point() cclass = { 'radial': RadialColor, 'cylindrical': CylinderColor, 'height': HeightColor }[geometry] from chimerax.core.undo import UndoState undo_state = UndoState('color %s' % geometry) for surf in surfs: cprev = surf.color_undo_state # Set origin and axis for coloring c = surf.scene_position.origin() if c0 is None else c0 if axis: # Scene coords a = axis.scene_coordinates(coordinate_system, session.main_view.camera) else: a = surf.scene_position.z_axis() cs = cclass(surf, palette, range, origin=c, axis=a, auto_recolor=auto_update) cs.set_vertex_colors() undo_state.add(surf, 'color_undo_state', cprev, surf.color_undo_state) session.undo.register(undo_state)
def uncartoon(session, atoms=None): '''Undisplay ribbons for specified residues. Parameters ---------- atoms : Atoms Hide ribbons for the specified residues. If no atoms are given then all ribbons are hidden. ''' if atoms is None: from chimerax.atomic import all_residues residues = all_residues(session) else: residues = atoms.unique_residues from chimerax.core.undo import UndoState undo_state = UndoState("cartoon hide") undo_state.add(residues, "ribbon_displays", residues.ribbon_displays, False) residues.ribbon_displays = False session.undo.register(undo_state)
def select(session, objects=None, polymer=None, residues=False, minimum_length=None, maximum_length=None, sequence=None): '''Select specified objects. Parameters ---------- objects : Objects Replace the current selection with the specified objects (typically atoms). If no objects are specified then everything is selected. residues : bool Extend atoms that are selected to containing residues if true (default false). polymer : Atoms Reduce the selection to include only atoms belonging to chains having a sequence that is the same as one of the sequences specified by the polymer option. minimum_length : float or None Exclude pseudobonds shorter than the specified length. If this option is specified all non-pseudobond objects are also excluded. maximum_length : float or None Exclude pseudobonds longer than the specified length. If this option is specified all non-pseudobond objects are also excluded. sequence : string or None Regular expression of sequence to match. Will be automatically upcased. ''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) from chimerax.core.undo import UndoState undo_state = UndoState("select") if sequence is None: objects = _filter_pseudobonds_by_length(objects, minimum_length, maximum_length) clear_selection(session, undo_state) modify_selection(objects, 'add', undo_state, full_residues = residues) if polymer is not None: polymer_selection(polymer, session, undo_state) else: clear_selection(session, undo_state) objects = _select_sequence(objects, sequence) modify_selection(objects, 'add', undo_state, full_residues = residues) session.undo.register(undo_state) report_selection(session)
def show(session, objects=None, what=None, target=None, only=False): '''Show specified atoms, bonds or models. Parameters ---------- objects : Objects or None Atoms, bonds or models to show. If None then all are shown. Objects that are already shown remain shown. what : 'atoms', 'bonds', 'pseudobonds', 'pbonds', 'cartoons', 'ribbons', 'surfaces', 'models' or None What to show. If None then 'atoms' if any atoms specified otherwise 'models'. target : set of "what" values, or None Alternative to the "what" option for specifying what to show. only : bool Show only the specified atoms/bonds/residues in each specified molecule. If what is models then hide models that are not specified. ''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) what_to_show = what_objects(target, what, objects) from chimerax.core.undo import UndoState undo_state = UndoState("show") if 'atoms' in what_to_show: show_atoms(session, objects, only, undo_state) if 'bonds' in what_to_show: show_bonds(session, objects, only, undo_state) if 'pseudobonds' in what_to_show or 'pbonds' in what_to_show: show_pseudobonds(session, objects, only, undo_state) if 'cartoons' in what_to_show or 'ribbons' in what_to_show: show_cartoons(session, objects, only, undo_state) if 'surfaces' in what_to_show: show_surfaces(session, objects, only, undo_state) if 'models' in what_to_show: show_models(session, objects, only, undo_state) session.undo.register(undo_state)
def cartoon_style(session, atoms=None, width=None, thickness=None, arrows=None, arrows_helix=None, arrow_scale=None, xsection=None, sides=None, bar_scale=None, bar_sides=None, ss_ends=None, mode_helix=None, mode_strand=None, radius=None, divisions=None, spline_normals=None): '''Set cartoon style options for secondary structures in specified structures. Parameters ---------- atoms : Atoms Set style for all secondary structure types that include the specified residues. If no atoms are given then style is set for all secondary structure types. width : floating point number Width of ribbons in angstroms. thickness : floating point number Thickness of ribbons in angstroms. arrows : boolean Whether to show arrow at ends of strands. arrows_helix : boolean Whether to show arrow at ends of helices. arrow_scale : floating point number Scale factor of arrow base width relative to strand or helix width. xsection : string Cross section type, one of "rectangle", "oval" or "barbell". sides : integer Number of sides for oval cross sections. divisions : integer Number of segments per residue bar_scale : floating point number Ratio of barbell connector to ends. bar_sides : integer Number of sides for barbell cross sections. ss_ends : string Length of helix/strand representation relative to backbone atoms. One of "default", "short" or "long". mode_helix : string Choose how helices are rendered. "default" uses ribbons through the alpha carbons. "tube" uses a tube along an arc so that the alpha carbons are on the surface of the tube. mode_strand : string Same argument values are mode_helix. radius: floating point number Radius of helices as cylinders ''' if atoms is None: from chimerax.atomic import all_residues, all_structures residues = all_residues(session) structures = all_structures(session) else: residues = atoms.unique_residues structures = residues.unique_structures import inspect argvalues = inspect.getargvalues(inspect.currentframe()) for name in argvalues.args: if name in ("session", "atoms"): continue if argvalues.locals.get(name, None) is not None: no_values = False break else: no_values = True if no_values: # if (width is None and thickness is None and arrows is None and # arrows_helix is None and arrow_scale is None and xsection is None and # sides is None and divisions is None and # bar_scale is None and bar_sides is None and # ss_ends is None and mode_helix is None and mode_strand is None and # radius is None and spline_normals is None): # No options, report current state and return indent = " -" for m in structures: mgr = m.ribbon_xs_mgr print(m) print(indent, "helix", "mode=%s" % _ModeHelixInverseMap[m.ribbon_mode_helix], "xsection=%s" % _XSectionInverseMap[mgr.style_helix], "width=%.2g" % (mgr.scale_helix[0] * 2), "height=%.2g" % (mgr.scale_helix[1] * 2), "arrow=%s" % mgr.arrow_helix, "arrow scale=%.2g" % (mgr.scale_helix_arrow[0][0] / mgr.scale_helix[0])) print(indent, "strand", "mode=%s" % _ModeStrandInverseMap[m.ribbon_mode_strand], "xsection=%s" % _XSectionInverseMap[mgr.style_sheet], "width=%.2g" % (mgr.scale_sheet[0] * 2), "height=%.2g" % (mgr.scale_sheet[1] * 2), "arrow=%s" % mgr.arrow_sheet, "arrow scale=%.2g" % (mgr.scale_sheet_arrow[0][0] / mgr.scale_sheet[0])) print(indent, "coil", "xsection=%s" % _XSectionInverseMap[mgr.style_coil], "width=%.2g" % (mgr.scale_coil[0] * 2), "height=%.2g" % (mgr.scale_coil[1] * 2)) print(indent, "nucleic", "xsection=%s" % _XSectionInverseMap[mgr.style_nucleic], "width=%.2g" % (mgr.scale_nucleic[0] * 2), "height=%.2g" % (mgr.scale_nucleic[1] * 2)) from chimerax.atomic.structure import structure_graphics_updater lod = structure_graphics_updater(session).level_of_detail print(indent, "divisions=%d" % lod.ribbon_divisions(m.num_ribbon_residues)) param = mgr.params[XSectionManager.STYLE_ROUND] print(indent, "oval parameters:", "sides=%d" % param["sides"]) param = mgr.params[XSectionManager.STYLE_PIPING] print(indent, "barbell parameters:", "sides=%d" % param["sides"], "scale=%.2g" % param["ratio"]) return is_helix = residues.is_helix is_strand = residues.is_strand polymer_types = residues.polymer_types from numpy import logical_and, logical_not is_coil = logical_and(logical_and(logical_not(is_helix), logical_not(is_strand)), polymer_types == Residue.PT_PROTEIN) coil_scale_changed = {} # Code uses half-width/thickness but command uses full width/thickness, # so we divide by two now so we will not need to do it multiple times if width is not None: width /= 2 if thickness is not None: thickness /= 2 from chimerax.core.undo import UndoState undo_state = UndoState("cartoon style") if is_coil.any(): # set coil parameters for m in structures: mgr = m.ribbon_xs_mgr if thickness is not None: coil_scale_changed[m] = True undo_state.add(mgr, "set_coil_scale", mgr.scale_coil, (thickness, thickness), "MA") mgr.set_coil_scale(thickness, thickness) if (xsection is not None and _XSectionMap[xsection] != XSectionManager.STYLE_PIPING): undo_state.add(mgr, "set_coil_style", mgr.style_coil, _XSectionMap[xsection], "M") mgr.set_coil_style(_XSectionMap[xsection]) if is_helix.any(): # set helix parameters for m in structures: mgr = m.ribbon_xs_mgr old_arrow_scale = None if width is not None or thickness is not None: w, h = mgr.scale_helix aw, ah = mgr.scale_helix_arrow[0] old_arrow_scale = aw / w if width is not None: w = width if thickness is not None: h = thickness undo_state.add(mgr, "set_helix_scale", mgr.scale_helix, (w, h), "MA") mgr.set_helix_scale(w, h) if arrow_scale is not None or old_arrow_scale is not None: w, h = mgr.scale_helix if arrow_scale is not None: aw = w * arrow_scale else: aw = w * old_arrow_scale ah = h cw, ch = mgr.scale_coil old = mgr.scale_helix_arrow[0] + mgr.scale_helix_arrow[1] undo_state.add(mgr, "set_helix_arrow_scale", old, (aw, ah, cw, ch), "MA") mgr.set_helix_arrow_scale(aw, ah, cw, ch) elif coil_scale_changed.get(m, False): aw, ah = mgr.scale_helix_arrow[0] cw, ch = mgr.scale_coil old = mgr.scale_helix_arrow[0] + mgr.scale_helix_arrow[1] undo_state.add(mgr, "set_helix_arrow_scale", old, (aw, ah, cw, ch), "MA") mgr.set_helix_arrow_scale(aw, ah, cw, ch) if arrows_helix is not None: undo_state.add(mgr, "set_helix_end_arrow", mgr.arrow_helix, arrows_helix, "M") mgr.set_helix_end_arrow(arrows_helix) if ss_ends is not None: # TODO: save undo data # These are the cases we deal with: # 1. coil->helix_start. (c_hs below) # The default is coil/helix (use coil for front and helix for back). # We do not change from the default because the twist from the # coil does not match the twist from the helix and we must use coil/helix # to look reasonable. # 2. helix_end->helix_start. (he_hs) # Default is helix/helix. # For "short", we use coil/helix. # For "long" we leave it helix/helix. # 3. sheet_end->helix_start. (se_hs) # Default is helix/helix. # For "short", we use coil/helix. # For "long" we use helix/helix. # 4. helix_end->coil. (he_c) # Default is arrow/coil. # For "short", we use arrow/coil. # For "long", we use helix/arrow. # 5. helix_end->helix_start. (he_hs) # Default is helix/arrow. # For "short", we use arrow/coil. # For "long", we use helix/arrow. # 6. helix_end->sheet_start. (he_ss) # Default is helix/arrow. # For "short", use it arrow/coil. # For "long", we use helix/arrow. # (Defaults are defined in XSectionManager class in ribbon.py.) if ss_ends == "default": # c_hs = (mgr.RIBBON_COIL, mgr.RIBBON_HELIX) he_hs_h = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX) se_hs_h = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX) h_he_c = (mgr.RIBBON_HELIX_ARROW, mgr.RIBBON_COIL) h_he_hs = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX_ARROW) h_he_ss = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX_ARROW) elif ss_ends == "short": # c_hs = (mgr.RIBBON_COIL, mgr.RIBBON_HELIX) he_hs_h = (mgr.RIBBON_COIL, mgr.RIBBON_HELIX) se_hs_h = (mgr.RIBBON_COIL, mgr.RIBBON_HELIX) h_he_c = (mgr.RIBBON_HELIX_ARROW, mgr.RIBBON_COIL) h_he_hs = (mgr.RIBBON_HELIX_ARROW, mgr.RIBBON_COIL) h_he_ss = (mgr.RIBBON_HELIX_ARROW, mgr.RIBBON_COIL) elif ss_ends == "long": # c_hs = (mgr.RIBBON_COIL, mgr.RIBBON_HELIX) he_hs_h = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX) se_hs_h = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX) h_he_c = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX_ARROW) h_he_hs = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX_ARROW) h_he_ss = (mgr.RIBBON_HELIX, mgr.RIBBON_HELIX_ARROW) else: raise ValueError("unexpected ss_ends value: %s" % ss_ends) # coil->helix_start->helix # mgr.set_transition(mgr.RC_COIL, mgr.RC_HELIX_START, mgr.RC_HELIX_MIDDLE, *c_hs) # mgr.set_transition(mgr.RC_COIL, mgr.RC_HELIX_START, mgr.RC_HELIX_END, *c_hs) # helix->helix_start->helix mgr.set_transition(mgr.RC_HELIX_END, mgr.RC_HELIX_START, mgr.RC_HELIX_MIDDLE, *he_hs_h) mgr.set_transition(mgr.RC_HELIX_END, mgr.RC_HELIX_START, mgr.RC_HELIX_END, *he_hs_h) # strand->helix_start->helix mgr.set_transition(mgr.RC_SHEET_END, mgr.RC_HELIX_START, mgr.RC_HELIX_MIDDLE, *se_hs_h) mgr.set_transition(mgr.RC_SHEET_END, mgr.RC_HELIX_START, mgr.RC_HELIX_END, *se_hs_h) # helix->helix_end->coil mgr.set_transition(mgr.RC_HELIX_START, mgr.RC_HELIX_END, mgr.RC_COIL, *h_he_c) mgr.set_transition(mgr.RC_HELIX_MIDDLE, mgr.RC_HELIX_END, mgr.RC_COIL, *h_he_c) # helix->helix_end->helix mgr.set_transition(mgr.RC_HELIX_START, mgr.RC_HELIX_END, mgr.RC_HELIX_START, *h_he_hs) mgr.set_transition(mgr.RC_HELIX_MIDDLE, mgr.RC_HELIX_END, mgr.RC_HELIX_START, *h_he_hs) # helix->helix_end->sheet mgr.set_transition(mgr.RC_HELIX_START, mgr.RC_HELIX_END, mgr.RC_SHEET_START, *h_he_ss) mgr.set_transition(mgr.RC_HELIX_MIDDLE, mgr.RC_HELIX_END, mgr.RC_SHEET_START, *h_he_ss) if xsection is not None: undo_state.add(mgr, "set_helix_style", mgr.style_helix, _XSectionMap[xsection], "M") mgr.set_helix_style(_XSectionMap[xsection]) if is_strand.any(): # set strand/sheet parameters for m in structures: mgr = m.ribbon_xs_mgr old_arrow_scale = None if width is not None or thickness is not None: w, h = mgr.scale_sheet aw, ah = mgr.scale_sheet_arrow[0] old_arrow_scale = aw / w if width is not None: w = width if thickness is not None: h = thickness undo_state.add(mgr, "set_sheet_scale", mgr.scale_sheet, (w, h), "MA") mgr.set_sheet_scale(w, h) if arrow_scale is not None or old_arrow_scale is not None: w, h = mgr.scale_sheet if arrow_scale is not None: aw = w * arrow_scale else: aw = w * old_arrow_scale ah = h cw, ch = mgr.scale_coil old = mgr.scale_sheet_arrow[0] + mgr.scale_sheet_arrow[1] undo_state.add(mgr, "set_sheet_arrow_scale", old, (aw, ah, cw, ch), "MA") mgr.set_sheet_arrow_scale(aw, ah, cw, ch) elif coil_scale_changed.get(m, False): aw, ah = mgr.scale_sheet_arrow[0] cw, ch = mgr.scale_coil old = mgr.scale_sheet_arrow[0] + mgr.scale_sheet_arrow[1] undo_state.add(mgr, "set_sheet_arrow_scale", old, (aw, ah, cw, ch), "MA") mgr.set_sheet_arrow_scale(aw, ah, cw, ch) if arrows is not None: undo_state.add(mgr, "set_sheet_end_arrow", mgr.arrow_sheet, arrows, "M") mgr.set_sheet_end_arrow(arrows) if ss_ends is not None: # TODO: save undo data if ss_ends == "default": # c_ss = (mgr.RIBBON_COIL, mgr.RIBBON_SHEET) he_ss_s = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET) se_ss_s = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET) s_se_c = (mgr.RIBBON_SHEET_ARROW, mgr.RIBBON_COIL) s_se_hs = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET_ARROW) s_se_ss = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET_ARROW) elif ss_ends == "short": # c_ss = (mgr.RIBBON_COIL, mgr.RIBBON_SHEET) he_ss_s = (mgr.RIBBON_COIL, mgr.RIBBON_SHEET) se_ss_s = (mgr.RIBBON_COIL, mgr.RIBBON_SHEET) s_se_c = (mgr.RIBBON_SHEET_ARROW, mgr.RIBBON_COIL) s_se_hs = (mgr.RIBBON_SHEET_ARROW, mgr.RIBBON_COIL) s_se_ss = (mgr.RIBBON_SHEET_ARROW, mgr.RIBBON_COIL) elif ss_ends == "long": # c_ss = (mgr.RIBBON_COIL, mgr.RIBBON_SHEET) he_ss_s = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET) se_ss_s = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET) s_se_c = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET_ARROW) s_se_hs = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET_ARROW) s_se_ss = (mgr.RIBBON_SHEET, mgr.RIBBON_SHEET_ARROW) else: raise ValueError("unexpected ss_ends value: %s" % ss_ends) # coil->sheet_start->helix # mgr.set_transition(mgr.RC_COIL, mgr.RC_SHEET_START, mgr.RC_SHEET_MIDDLE, *c_ss) # mgr.set_transition(mgr.RC_COIL, mgr.RC_SHEET_START, mgr.RC_SHEET_END, *c_ss) # sheet->sheet_start->helix mgr.set_transition(mgr.RC_HELIX_END, mgr.RC_SHEET_START, mgr.RC_SHEET_MIDDLE, *he_ss_s) mgr.set_transition(mgr.RC_HELIX_END, mgr.RC_SHEET_START, mgr.RC_SHEET_END, *he_ss_s) # sheet->sheet_start->helix mgr.set_transition(mgr.RC_SHEET_END, mgr.RC_SHEET_START, mgr.RC_SHEET_MIDDLE, *se_ss_s) mgr.set_transition(mgr.RC_SHEET_END, mgr.RC_SHEET_START, mgr.RC_SHEET_END, *se_ss_s) # sheet->sheet_end->coil mgr.set_transition(mgr.RC_SHEET_START, mgr.RC_SHEET_END, mgr.RC_COIL, *s_se_c) mgr.set_transition(mgr.RC_SHEET_MIDDLE, mgr.RC_SHEET_END, mgr.RC_COIL, *s_se_c) # sheet->sheet_end->helix mgr.set_transition(mgr.RC_SHEET_START, mgr.RC_SHEET_END, mgr.RC_HELIX_START, *s_se_hs) mgr.set_transition(mgr.RC_SHEET_MIDDLE, mgr.RC_SHEET_END, mgr.RC_HELIX_START, *s_se_hs) # sheet->sheet_end->sheet mgr.set_transition(mgr.RC_SHEET_START, mgr.RC_SHEET_END, mgr.RC_SHEET_START, *s_se_ss) mgr.set_transition(mgr.RC_SHEET_MIDDLE, mgr.RC_SHEET_END, mgr.RC_SHEET_START, *s_se_ss) if xsection is not None: undo_state.add(mgr, "set_sheet_style", mgr.style_helix, _XSectionMap[xsection], "M") mgr.set_sheet_style(_XSectionMap[xsection]) if (polymer_types == Residue.PT_NUCLEIC).any(): # set nucleic parameters for m in structures: mgr = m.ribbon_xs_mgr if width is not None or thickness is not None: w, h = mgr.scale_nucleic # Invert width and thickness since nucleic cross section # is perpendicular to protein cross section if width is not None: h = width if thickness is not None: w = thickness undo_state.add(mgr, "set_nucleic_scale", mgr.scale_nucleic, (w, h), "MA") mgr.set_nucleic_scale(w, h) if xsection is not None: undo_state.add(mgr, "set_nucleic_style", mgr.style_nucleic, _XSectionMap[xsection], "M") mgr.set_nucleic_style(_XSectionMap[xsection]) # process sides, bar_sides and bar_scale oval_params = {} bar_params = {} if sides is not None: oval_params["sides"] = sides if oval_params: for m in structures: mgr = m.ribbon_xs_mgr old_param = mgr.params[XSectionManager.STYLE_ROUND].copy() old_param["style"] = XSectionManager.STYLE_ROUND mgr.set_params(XSectionManager.STYLE_ROUND, **oval_params) new_param = mgr.params[XSectionManager.STYLE_ROUND].copy() new_param["style"] = XSectionManager.STYLE_ROUND undo_state.add(mgr, "set_params", old_param, new_param, "MK") if bar_scale is not None: bar_params["ratio"] = bar_scale if bar_sides is not None: bar_params["sides"] = bar_sides if bar_params: for m in structures: mgr = m.ribbon_xs_mgr old_param = mgr.params[XSectionManager.STYLE_PIPING].copy() old_param["style"] = XSectionManager.STYLE_PIPING mgr.set_params(XSectionManager.STYLE_PIPING, **bar_params) new_param = mgr.params[XSectionManager.STYLE_PIPING].copy() new_param["style"] = XSectionManager.STYLE_PIPING undo_state.add(mgr, "set_params", old_param, new_param, "MK") # process divisions which is actually handled by level of detail if divisions is not None: from chimerax.atomic.structure import structure_graphics_updater gu = structure_graphics_updater(session) prev_divisions = gu.level_of_detail.ribbon_fixed_divisions undo_state.add(gu, "set_ribbon_divisions", prev_divisions, divisions, option = 'M') gu.set_ribbon_divisions(divisions) # process modes if mode_helix is not None: mode = _ModeHelixMap.get(mode_helix, None) for m in structures: undo_state.add(m, "ribbon_mode_helix", m.ribbon_mode_helix, mode) m.ribbon_mode_helix = mode if mode_strand is not None: mode = _ModeStrandMap.get(mode_strand, None) for m in structures: undo_state.add(m, "ribbon_mode_strand", m.ribbon_mode_strand, mode) m.ribbon_mode_strand = mode # process radius if radius is not None: if radius == "auto": radius = None for m in structures: mgr = m.ribbon_xs_mgr undo_state.add(mgr, "set_tube_radius", mgr.tube_radius, radius, "M") mgr.set_tube_radius(radius) if spline_normals is not None: for m in structures: undo_state.add(m, "spline_normals", m.spline_normals, spline_normals) m.spline_normals = spline_normals session.undo.register(undo_state)
def mlp(session, atoms=None, method="fauchere", spacing=1.0, max_distance=5.0, nexp=3.0, color=True, palette=None, range=None, surfaces=[], map=False): '''Display Molecular Lipophilic Potential for a single model. Parameters ---------- atoms : Atoms Color surfaces for these atoms using MLP map. Only amino acid residues are used. method : 'dubost','fauchere','brasseur','buckingham','type5' Distance dependent function to use for calculation spacing : float Grid spacing, default 1 Angstrom. max_distance : float Maximum distance from atom to sum lipophilicity. Default 5 Angstroms. nexp : float The buckingham method uses this numerical exponent. color : bool Whether to color molecular surfaces. They are created if they don't yet exist. palette : Colormap Color palette for coloring surfaces. Default is lipophilicity colormap (orange lipophilic, blue lipophobic). range : 2-tuple of float Range of lipophilicity values defining ends of color map. Default is -20,20 surfaces : list of Surface models If the color options is true then these surfaces are colored instead of computing surfaces. map : bool Whether to open a volume model of lipophilicity values ''' if atoms is None: from chimerax.atomic import all_atoms atoms = all_atoms(session) from chimerax.atomic import Residue patoms = atoms[atoms.residues.polymer_types == Residue.PT_AMINO] if len(patoms) == 0: from chimerax.core.errors import UserError raise UserError('mlp: no amino acids specified') if palette is None: from chimerax.core.colors import BuiltinColormaps cmap = BuiltinColormaps['lipophilicity'] else: cmap = palette if range is None and not cmap.values_specified: range = (-20, 20) # Color surfaces by lipophilicity if color: # Compute surfaces if not already created from chimerax.surface import surface surfs = surface(session, patoms) if len(surfaces) == 0 else surfaces from chimerax.core.undo import UndoState undo_state = UndoState('mlp') for s in surfs: satoms = s.atoms name = 'mlp ' + s.name.split(maxsplit=1)[0] v = mlp_map(session, satoms, method, spacing, max_distance, nexp, name, open_map=map) from chimerax.surface import color_surfaces_by_map_value color_surfaces_by_map_value(satoms, map=v, palette=cmap, range=range, undo_state=undo_state) session.undo.register(undo_state) else: name = 'mlp map' v = mlp_map(session, patoms, method, spacing, max_distance, nexp, name, open_map=map)
def cmd_coulombic(session, atoms, *, surfaces=None, his_scheme=None, offset=1.4, spacing=1.0, padding=5.0, map=False, palette=None, range=None, dist_dep=True, dielectric=4.0): if map: session.logger.warning( "Computing electrostatic volume map not yet supported") session.logger.status("Computing Coulombic charge surface%s" % ("/volume" if map else "")) if palette is None: from chimerax.core.colors import BuiltinColormaps cmap = BuiltinColormaps["red-white-blue"] if not cmap.values_specified: rmin, rmax = (-10.0, 10.0) if range is None else range cmap = cmap.linear_range(rmin, rmax) session.logger.status("Matching atoms to surfaces", secondary=True) atoms_per_surf = [] from chimerax.atomic import all_atomic_structures, MolecularSurface, all_atoms if atoms is None: if surfaces is None: # surface all chains for struct in all_atomic_structures(session): # don't create surface until charges checked if struct.num_chains == 0: atoms_per_surf.append((struct.atoms, None, None)) else: for chain in struct.chains: atoms_per_surf.append( (chain.existing_residues.atoms, None, None)) else: for srf in surfaces: if isinstance(srf, MolecularSurface): atoms_per_surf.append((srf.atoms, None, srf)) else: atoms_per_surf.append((all_atoms(session), None, srf)) else: if surfaces is None: # on a per-structure basis, determine if the atoms contain any polymers, and if so then # surface those chains (and not non-polymers); otherwise surface the atoms by_chain = {} for struct, chain_id, chain_atoms in atoms.by_chain: chains = chain_atoms.unique_residues.unique_chains if chains: by_chain.setdefault(struct, {})[chains[0]] = chain_atoms for struct, struct_atoms in atoms.by_structure: try: for chain, shown_atoms in by_chain[struct].items(): chain_atoms = chain.existing_residues.atoms atoms_per_surf.append( (chain_atoms, chain_atoms & shown_atoms, None)) except KeyError: atoms_per_surf.append((struct_atoms, None, None)) else: for srf in surfaces: atoms_per_surf.append((atoms, None, srf)) # check whether the atoms have charges, and if not, that we know how to assign charges # to the requested atoms problem_residues = set() needs_assignment = set() for surf_atoms, shown_atoms, srf in atoms_per_surf: for r in surf_atoms.unique_residues: if getattr(r, '_coulombic_his_scheme', his_scheme) != his_scheme: # should only be set on HIS residues needs_assignment.add(r) else: for a in r.atoms: try: a.charge + 1.0 except (AttributeError, TypeError): if r.name in chargeable_residues: needs_assignment.add(r) else: problem_residues.add(r.name) break if problem_residues: session.logger.status("") from chimerax.core.commands import commas raise UserError( "Don't know how to assign charges to the following residue types: %s" % commas(problem_residues, conjunction='and')) if needs_assignment: session.logger.status("Assigning charges", secondary=True) from .coulombic import assign_charges, ChargeError try: assign_charges(session, needs_assignment, his_scheme) except ChargeError as e: session.logger.status("") raise UserError(str(e)) # Since electrostatics are long range, unlike mlp, don't compute a map (with a distance cutoff) # by default. Instead, compute the values at the surface vertices directly. Only compute a # map afterward if requested. from chimerax.core.undo import UndoState undo_state = UndoState('coulombic') undo_owners = [] undo_old_vals = [] undo_new_vals = [] for surf_atoms, shown_atoms, srf in atoms_per_surf: if srf is None: session.logger.status("Creating surface", secondary=True) from chimerax.surface import surface data = [(surf.atoms, surf) for surf in surface( session, surf_atoms if shown_atoms is None else shown_atoms)] else: data = [(surf_atoms, srf)] session.logger.status("Computing electrostatics", secondary=True) for charged_atoms, target_surface in data: undo_owners.append(target_surface) undo_old_vals.append(target_surface.vertex_colors) if target_surface.normals is None: session.logger.warning( "Surface %s has no vertex normals set, using distance from surface" " of 0 instead of %g" % (target_surface, offset)) target_points = target_surface.vertices else: target_points = target_surface.vertices + offset * target_surface.normals import numpy, os from ._esp import potential_at_points cpu_count = os.cpu_count() vertex_values = potential_at_points( target_surface.scene_position.transform_points(target_points), charged_atoms.scene_coords, numpy.array([a.charge for a in charged_atoms], dtype=numpy.double), dist_dep, dielectric, 1 if cpu_count is None else cpu_count) rgba = cmap.interpolated_rgba(vertex_values) from numpy import uint8 rgba8 = (255 * rgba).astype(uint8) target_surface.vertex_colors = rgba8 undo_new_vals.append(rgba8) undo_state.add(undo_owners, "vertex_colors", undo_old_vals, undo_new_vals, option="S") session.undo.register(undo_state) session.logger.status("", secondary=True) session.logger.status("Finished computing Coulombic charge surface%s" % ("/volume" if map else ""))
def nucleotides(session, representation, *, glycosidic=default.GLYCOSIDIC, show_orientation=default.ORIENT, thickness=default.THICKNESS, hide_atoms=default.HIDE, shape=default.SHAPE, dimensions=default.DIMENSIONS, radius=None, show_stubs=default.SHOW_STUBS, base_only=default.BASE_ONLY, stubs_only=default.STUBS_ONLY, objects=None, create_undo=True): if objects is None: objects = all_objects(session) residues = objects.atoms.unique_residues from chimerax.atomic import Residue residues = residues.filter(residues.polymer_types == Residue.PT_NUCLEIC) if len(residues) == 0: return if create_undo: undo_state = UndoState('nucleotides %s' % representation) nucleic_undo = _NucleicUndo('nucleotides %s' % representation, session, representation, glycosidic, show_orientation, thickness, hide_atoms, shape, dimensions, radius, show_stubs, base_only, stubs_only, residues) undo = UndoAggregateAction('nucleotides %s' % representation, [undo_state, nucleic_undo]) if representation == 'atoms': # hide filled rings if create_undo: undo_state.add(residues, "ring_displays", residues.ring_displays, False) residues.ring_displays = False # reset nucleotide info NA.set_normal(residues) elif representation == 'fill': # show filled rings if create_undo: undo_state.add(residues, "ring_displays", residues.ring_displays, True) residues.ring_displays = True # set nucleotide info if show_orientation: NA.set_orient(residues) else: NA.set_normal(residues) elif representation.endswith('slab'): if radius is None: radius = default.TUBE_RADIUS if dimensions is None: if shape == 'ellipsoid': dimensions = 'small' else: dimensions = 'long' if representation == 'slab': if create_undo: undo_state.add(residues, "ring_displays", residues.ring_displays, True) residues.ring_displays = True show_gly = True else: show_gly = glycosidic if show_gly: info = NA.find_dimensions(dimensions) show_gly = info[NA.ANCHOR] != NA.RIBOSE NA.set_slab(representation, residues, dimensions=dimensions, thickness=thickness, orient=show_orientation, shape=shape, show_gly=show_gly, hide=hide_atoms, tube_radius=radius) elif representation in ('ladder', 'stubs'): if radius is None: radius = default.RUNG_RADIUS stubs_only = representation == 'stubs' NA.set_ladder(residues, rung_radius=radius, stubs_only=stubs_only, show_stubs=show_stubs, skip_nonbase_Hbonds=base_only, hide=hide_atoms) if create_undo: session.undo.register(undo)
def size(session, objects=None, atom_radius=None, stick_radius=None, pseudobond_radius=None, ball_scale=None): '''Set the sizes of atom and bonds. Parameters ---------- objects : Objects Change the size of these atoms, bonds and pseudobonds. If not specified then all are changed. atom_radius : float or "default" New radius value for atoms. stick_radius : float New radius value for bonds shown in stick style. pseudobond_radius : float New radius value for pseudobonds. ball_scale : float Multiplier times atom radius for determining atom size in ball style (default 0.3). ''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) from chimerax.core.undo import UndoState undo_state = UndoState("size") what = [] if atom_radius is not None: atoms = objects.atoms if atom_radius == 'default': undo_state.add(atoms, "radii", atoms.radii, atoms.default_radii) atoms.radii = atoms.default_radii else: undo_state.add(atoms, "radii", atoms.radii, atom_radius) atoms.radii = atom_radius what.append('%d atom radii' % len(atoms)) if stick_radius is not None: b = objects.bonds undo_state.add(b, "radii", b.radii, stick_radius) b.radii = stick_radius # If singleton atom specified then set the single-atom stick radius. for s, atoms in objects.atoms.by_structure: if (atoms.num_bonds == 0).any(): s.bond_radius = stick_radius what.append('%d bond radii' % len(b)) if pseudobond_radius is not None: pb = objects.pseudobonds undo_state.add(pb, "radii", pb.radii, pseudobond_radius) pb.radii = pseudobond_radius from chimerax.atomic import concatenate what.append('%d pseudobond radii' % len(pb)) if ball_scale is not None: mols = objects.residues.unique_structures for s in mols: undo_state.add(s, "ball_scale", s.ball_scale, ball_scale) s.ball_scale = ball_scale what.append('%d ball scales' % len(mols)) if what: msg = 'Changed %s' % ', '.join(what) log = session.logger log.status(msg) log.info(msg) session.undo.register(undo_state)
def style(session, objects=None, atom_style=None, dashes=None, ring_fill=None): '''Set the atom and bond display styles. Parameters ---------- objects : Objects Change the style of these atoms, bonds and pseudobonds. If not specified then all atoms are changed. atom_style : "sphere", "ball" or "stick" Controls how atoms and bonds are depicted. dashes : int Optional number of dashes shown for pseudobonds. ring_fill : Optional "thick", "thin", or "off". ''' if objects is None: from chimerax.core.objects import all_objects objects = all_objects(session) from chimerax.core.commands import plural_form from chimerax.core.undo import UndoState undo_state = UndoState("style") what = [] if atom_style is not None: from chimerax.atomic import Atom s = { 'sphere': Atom.SPHERE_STYLE, 'ball': Atom.BALL_STYLE, 'stick': Atom.STICK_STYLE, }[atom_style.lower()] atoms = objects.atoms undo_state.add(atoms, "draw_modes", atoms.draw_modes, s) atoms.draw_modes = s what.append('%d %s' % (len(atoms), plural_form(atoms, 'atom style'))) if dashes is not None: pbgs = objects.pseudobonds.unique_groups for pbg in pbgs: undo_state.add(pbg, "dashes", pbg.dashes, dashes) pbg.dashes = dashes what.append('%d %s' % (len(pbgs), plural_form(pbgs, 'pseudobond dash'))) if ring_fill is not None: res = objects.residues if ring_fill == 'on': undo_state.add(res, "ring_displays", res.ring_displays, True) res.ring_displays = True elif ring_fill == 'off': undo_state.add(res, "ring_displays", res.ring_displays, False) res.ring_displays = False elif ring_fill == 'thin': undo_state.add(res, "ring_displays", res.ring_displays, True) undo_state.add(res, "thin_rings", res.thin_rings, True) res.ring_displays = True res.thin_rings = True elif ring_fill == 'thick': undo_state.add(res, "ring_displays", res.ring_displays, True) undo_state.add(res, "thin_rings", res.thin_rings, False) res.ring_displays = True res.thin_rings = False what.append('%d %s' % (len(res), plural_form(res, 'residue ring style'))) if what: msg = 'Changed %s' % ', '.join(what) log = session.logger log.status(msg) log.info(msg) session.undo.register(undo_state)