Source code for schrodinger.application.matsci.maestrocmds
"""
Common Maestro commands.
Copyright Schrodinger, LLC. All rights reserved.
"""
import contextlib
import random
import seaborn as sns
import schrodinger
maestro = schrodinger.get_maestro()
XKCD = 'xkcd'
CRAYON = 'crayon'
PALETTES = {
    XKCD: (sns.xkcd_palette, sns.xkcd_rgb),
    CRAYON: (sns.crayon_palette, sns.crayons)
}
[docs]def get_colors(palette=None, seed=None, n_colors=10, normalized=False):
    """
    Return RGB color tuples.
    :type palette: str
    :param palette: if not a palette in PALETTES then this is the
        palette kwarg passed to seaborn.color_palette
    :type seed: None or int
    :param seed: if given randomize the RGB color tuples using the
        given seed
    :type n_colors: int
    :param n_colors: the number of colors to return
    :type normalized: bool
    :param normalized: whether to normalize the RGB tuples
    :rtype: list
    :return: contains RGB color tuples
    """
    pair = PALETTES.get(palette)
    if pair:
        rgb_getter, color_dict = pair
        rgbs = rgb_getter(color_dict.keys())
    else:
        rgbs = sns.color_palette(palette=palette, n_colors=n_colors)
    if seed:
        myrandom = random.Random(seed)
        myrandom.shuffle(rgbs)
    rgbs = rgbs[:n_colors]
    if not normalized:
        rgbs = [tuple(int(255 * item) for item in rgb) for rgb in rgbs]
    return rgbs 
def _get_color_set_1(seed=123, n_colors=20):
    """
    Return RGB color tuples for set 1.
    :type seed: None or int
    :param seed: if given randomize the RGB color tuples using the
        given seed
    :type n_colors: int
    :param n_colors: the number of colors to return
    :rtype: list
    :return: contains RGB color tuples
    """
    # the following gives 10 unique colors (this is the maximum number
    # of unique colors avilable with the given options before it starts
    # reusing colors)
    rgbs = get_colors(palette=None, seed=None, n_colors=10)
    n_colors = n_colors - 10
    if n_colors > 0:
        rgbs += get_colors(palette=CRAYON, seed=seed, n_colors=n_colors)
    return rgbs
[docs]def normalize_rgb_color(rgb):
    """
    Normalize the given color.
    :type rgb: tuple
    :param rgb: an RGB triple of integers in [0, 255]
    :rtype: tuple
    :return: normalized RGB triple of floats in [0, 1]
    """
    return tuple(x / 255 for x in rgb) 
[docs]def get_atoms_asl(idxs):
    """
    Return the atoms ASL.
    :type idxs: list(int)
    :param idxs: atom indices
    :rtype: str
    :return: the atoms ASL
    """
    idxs_str = ','.join(map(str, idxs))
    return f'atom.n {idxs_str}' 
[docs]def execute_cmd(cmd):
    """
    Execute the Maestro command.
    :type cmd: str
    :param cmd: the Maestro command
    """
    if maestro:
        maestro.command(cmd) 
[docs]def color_atoms(rgb, idxs):
    """
    Color atoms in the Maestro WS.
    :type rgb: tuple
    :param rgb: an RGB triple of integers in [0, 255]
    :type idxs: list(int)
    :param idxs: atom indices
    """
    cmd = 'coloratomrgb red=%s green=%s blue=%s' % rgb
    asl = get_atoms_asl(idxs)
    execute_cmd(f'{cmd} {asl}') 
[docs]def color_atom_groups(all_idxs, rgbs=None):
    """
    Color groups of atoms in the Maestro WS.
    :type all_idxs: list(list(int))
    :param all_idxs: groups of atom indices
    :type rgbs: list(tuple) or None
    :param rgbs: RGB triples of integers in [0, 255]
        for coloring the different groups of atoms, if
        None then some defaults colors are used
    """
    if not rgbs:
        # seed of 4 gives decent colors
        rgbs = _get_color_set_1(seed=4, n_colors=len(all_idxs))
    assert len(all_idxs) <= len(rgbs)
    for idxs, rgb in zip(all_idxs, rgbs):
        color_atoms(rgb, idxs) 
[docs]@contextlib.contextmanager
def select_all_atoms():
    """
    Context manager to temporarily select all atoms in
    the Maestro WS.
    """
    execute_cmd('workspaceselectionclear')
    execute_cmd('workspaceselectionreplacenoundo all')
    yield
    execute_cmd('workspaceselectionclearnoundo')
    execute_cmd('workspaceselectionclear') 
[docs]def select_atoms(index):
    """
    Select specified atoms in Maestro WS
    :type index: list
    :param index: list of atom indexes
    """
    execute_cmd('workspaceselectionreplace atom.n ' + ','.join(map(str, index))) 
[docs]def color_by_element():
    """
    Color all atoms in the Maestro WS by element.
    """
    with select_all_atoms():
        execute_cmd('colorscheme scheme="Element" at.selected') 
[docs]def set_ballnstick_repr(idxs):
    """
    Set the representation of atoms in the Maestro WS to ball-and-stick.
    :type idxs: list(int)
    :param idxs: atom indices
    """
    maestro.command('repatombonds all')
    cmd = 'repatom  rep=ballnstick'
    asl = get_atoms_asl(idxs)
    execute_cmd(f'{cmd} {asl}') 
[docs]def set_included(entry_id):
    """
    Set the included entry to that of the given entry ID.
    :type entry_id: str
    :param entry_id: the entry ID
    """
    execute_cmd(f'entrywsincludeonly entry {entry_id}')