Example #1
0
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)
Example #2
0
    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
Example #3
0
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)
Example #4
0
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)
Example #5
0
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)
Example #6
0
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)
Example #7
0
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)
Example #8
0
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)
Example #9
0
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)
Example #10
0
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)
Example #11
0
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)
Example #12
0
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)
Example #13
0
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)
Example #14
0
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)
Example #15
0
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)
Example #16
0
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)
Example #17
0
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 ""))
Example #18
0
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)
Example #19
0
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)
Example #20
0
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)