#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
nmrstarlib.csviewer
~~~~~~~~~~~~~~~~~~~
This module provides the :class:`~nmrstarlib.csviewer.CSViewer` class - Chemical Shifts Viewer
that visualizes chemical shifts values.
"""
from graphviz import Source
from . import fileio
[docs]class CSViewer(object):
"""Chemical Shifts Viewer uses :meth:`~nmrstarlib.nmrstarlib.NMRStarFile.chem_shifts_by_residue`
method to get chemical shifts organized by residue and visualizes chemical shifts values using the
Graphviz (http://www.graphviz.org/) DOT Languge description.
"""
dot_template = '''digraph {{
compound=true
fontname="Inconsolata, Consolas"
fontsize=10
margin="0,0"
ranksep=0.2
rankdir=LR
penwidth=0.5
node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
edge [fontname="Inconsolata, Consolas", fontsize=10]
subgraph cluster1 {{
margin="10,10"
labeljust="left"
node [shape=Mrecord, style=filled, colorscheme=spectral11]
{{
{}
}}
edge [arrowhead=none]
{}
}}
}}
'''
[docs] def __init__(self, from_path, amino_acids=None, atoms=None, amino_acids_and_atoms=None, filename=None, csview_format="svg", nmrstar_version="3"):
"""CSViewer initializer.
:param str from_path: Path to single NMR-STAR file or BMRB id.
:param amino_acids: Sequence of amino acids three letter codes, e.g. 'ALA', 'GLY', 'SER', etc. Leave as `None` to include everything.
:type amino_acids: :py:class:`list` or :py:class:`tuple`
:param atoms: Sequence of atom types, e.g. 'CA', 'CB', 'HA', etc. Leave as `None` to include everything.
:type atoms: :py:class:`list` or :py:class:`tuple`
:param dict amino_acids_and_atoms: Amino acid and its atoms key-value pairs.
:param str filename: Output filename chemical shifts graph to be saved.
:param str csview_format: `svg`, `png`, `pdf`. See http://www.graphviz.org/doc/info/output.html for all available formats.
:param str nmrstar_version: Version of NMR-STAR format to use for look up chemichal shifts loop.
:return: None
:rtype: :py:obj:`None`
"""
self.from_path = from_path
self.amino_acids = amino_acids
self.atoms = atoms
self.amino_acids_and_atoms = amino_acids_and_atoms
self.filename = filename
self.csview_format = csview_format
self.nmrstar_version = nmrstar_version
[docs] def csview(self, view=False):
"""View chemical shift values organized by amino acid residue.
:param view: Open in default image viewer or save file in current working directory quietly.
:type view: :py:obj:`True` or :py:obj:`False`
:return: None
:rtype: :py:obj:`None`
"""
for starfile in fileio.read_files(self.from_path):
chains = starfile.chem_shifts_by_residue(amino_acids=self.amino_acids,
atoms=self.atoms,
amino_acids_and_atoms=self.amino_acids_and_atoms,
nmrstar_version=self.nmrstar_version)
for idx, chemshifts_dict in enumerate(chains):
nodes = []
edges = []
for seq_id in chemshifts_dict:
aaname = "{}_{}".format(chemshifts_dict[seq_id]["AA3Code"], seq_id)
label = '"{{{}|{}}}"'.format(seq_id, chemshifts_dict[seq_id]["AA3Code"])
color = 8
aanode_entry = " {} [label={}, fillcolor={}]".format(aaname, label, color)
nodes.append(aanode_entry)
currnodename = aaname
for atom_type in chemshifts_dict[seq_id]:
if atom_type in ["AA3Code", "Seq_ID"]:
continue
else:
atname = "{}_{}".format(aaname, atom_type)
label = '"{{{}|{}}}"'.format(atom_type, chemshifts_dict[seq_id][atom_type])
if atom_type.startswith("H"):
color = 4
elif atom_type.startswith("C"):
color = 6
elif atom_type.startswith("N"):
color = 10
else:
color = 8
atnode_entry = "{} [label={}, fillcolor={}]".format(atname, label, color)
nextnodename = atname
nodes.append(atnode_entry)
edges.append("{} -> {}".format(currnodename, nextnodename))
currnodename = nextnodename
if self.filename is None:
filename = "{}_{}".format(starfile.id, idx)
else:
filename = "{}_{}".format(self.filename, idx)
src = Source(self.dot_template.format("\n".join(nodes), "\n".join(edges)), format=self.csview_format)
src.render(filename=filename, view=view)