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}')