Source code for aquaduct.visual.quickplot

# -*- coding: utf-8 -*-

# Aqua-Duct, a tool facilitating analysis of the flow of solvent molecules in molecular dynamic simulations
# Copyright (C) 2016-2018  Tomasz Magdziarz, Alicja Płuciennik, Michał Stolarczyk <info@aquaduct.pl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import numpy as np

import matplotlib.pyplot as plt

from aquaduct.geom import traces
from aquaduct.utils.helpers import list_blocks_to_slices
from aquaduct.visual.helpers import color_codes, cc


# matplotlib specific
# mpl color converter
# cc = lambda c,alpha=1.0 : colorConverter.to_rgba(c,alpha=alpha)


[docs]def yield_spath_len_and_smooth_diff_in_types_slices(sp, smooth=None, smooth_len=None, smooth_diff=None, types='etypes'): if smooth is not None: smooth_len = smooth smooth_diff = smooth # len coords = sp.get_coords_cont(smooth=smooth_len) dif = traces.diff(coords) ldif = np.cumsum(dif) # diff if smooth_diff != smooth_len: coords = sp.get_coords_cont(smooth=smooth_diff) dif = traces.diff(coords) # ldif = np.array(range(len(dif))) # same OX if types == 'etypes': etypes = sp.etypes_cont elif types == 'types': etypes = sp.types_cont for sl in list_blocks_to_slices(etypes): etype = etypes[sl] ld = ldif[sl] sd = dif[sl] while len(etype) > len(ld): etype.pop(-1) yield ld, sd, etype
[docs]def plot_colorful_lines(x, y, c, **kwargs): sls = list(list_blocks_to_slices(c)) n = len(sls) for nr, sl in enumerate(sls): a = x[sl] b = y[sl] color = c[sl][-1] if nr == 0: plt.plot(a, b, color=color, **kwargs) last_a = a[-1] last_b = b[-1] last_color = color else: mid_a = (last_a + a[0]) / 2 mid_b = (last_b + b[0]) / 2 if nr == n - 1: plt.plot([last_a, mid_a], [last_b, mid_b], color=last_color, **kwargs) plt.plot([mid_a, a[0]], [mid_b, b[0]], color=color, **kwargs) plt.plot(a, b, color=color, **kwargs) else: plt.plot([last_a, mid_a], [last_b, mid_b], color=last_color, **kwargs) plt.plot([mid_a, a[0]], [mid_b, b[0]], color=color, **kwargs) plt.plot(a, b, color=color, **kwargs) last_a = a[-1] last_b = b[-1] last_color = color
[docs]def spaths_spectra(spaths, **kwargs): spectra = [] minx = None maxx = None for sp in spaths: xyc = list(spath_spectrum(sp, **kwargs)) xy = np.array([(x, y) for x, y, c in xyc]) c = list([c for x, y, c in xyc]) x = xy[:, 0] y = xy[:, 1] spectra.append((y, c)) if maxx is None: maxx = max(x) else: maxx = max(maxx, max(x)) if minx is None: minx = min(x) else: minx = min(minx, min(x)) for (y, c) in spectra: plot_colorful_lines(np.linspace(minx, maxx, len(c)), y, c)
[docs]def plot_spath_spectrum(sp, **kwargs): xyc = list(spath_spectrum(sp, **kwargs)) xy = np.array([(x, y) for x, y, c in xyc]) c = list([c for x, y, c in xyc]) plot_colorful_lines(xy[:, 0], xy[:, 1], c)
[docs]def spath_spectrum(sp, **kwargs): lsdt = list(yield_spath_len_and_smooth_diff_in_types_slices(sp, **kwargs)) n = len(lsdt) last_l = None last_sd = None last_t = None last_color = None for nr, (l, sd, t) in enumerate(lsdt): color = color_codes(t[-1]) if nr == 0: for ll, ssdd in zip(l, sd): yield ll, ssdd, color # plt.plot(l, sd, color=color) last_l = l[-1] last_sd = sd[-1] last_color = color else: mid_l = (last_l + l[0]) / 2 mid_sd = (last_sd + sd[0]) / 2 if nr == n - 1: # for ll, ssdd in zip([last_l, mid_l], [last_sd, mid_sd]): # yield ll, ssdd, last_color # plt.plot([last_l, mid_l], [last_sd, mid_sd], color=last_color) # for ll, ssdd in zip([mid_l, l[0]], [mid_sd, sd[0]]): # yield ll, ssdd, color # plt.plot([mid_l, l[0]], [mid_sd, sd[0]], color=color) for ll, ssdd in zip(l, sd): yield ll, ssdd, color # plt.plot(l, sd, color=color) else: # for ll, ssdd in zip([last_l, mid_l], [last_sd, mid_sd]): # yield ll, ssdd, last_color # plt.plot([last_l, mid_l], [last_sd, mid_sd], color=last_color) # for ll, ssdd in zip([mid_l, l[0]], [mid_sd, sd[0]]): # yield ll, ssdd, color # plt.plot([mid_l, l[0]], [mid_sd, sd[0]], color=color) for ll, ssdd in zip(l, sd): yield ll, ssdd, color # plt.plot(l, sd, color=color) last_l = l[-1] last_sd = sd[-1] last_color = color
[docs]def showit(gen): def patched(*args, **kwargs): obj = gen(*args, **kwargs) plt.show() return obj return patched
[docs]def get_ax3d(fig, sub=111): return fig.add_subplot(sub, projection='3d')
[docs]class SimpleTracePlotter(object):
[docs] def plot_line(self, coords, color, **kwargs): raise NotImplementedError('This is abstract class. Missing implementaion in a child class.')
''' def path_trace(self,path,color=('r','g','b'), plot_in=True, plot_object=True, plot_out=True, **kwargs): raise NotImplementedError('This is base class.') '''
[docs] def single_trace(self, coords, color='r', **kwargs): # coords is a trace # color is a single color color = cc(color) coords = np.array(coords) # call plot_line self.plot_line(coords, color, **kwargs)
[docs] def path_trace(self, path, color=('r', 'g', 'b'), plot_in=True, plot_object=True, plot_out=True, **kwargs): # path is a tuple of length 3, its elements represent in,object, out parts of path # color is a tuple of length 3, its elements correspond to colors of consecutive path parts color = map(cc, color) for nr, trace in enumerate(traces.midpoints(path)): # mid points! if len(trace) > 0: if (nr == 0 and plot_in) or (nr == 1 and plot_object) or (nr == 2 and plot_out): self.single_trace(trace, color=color[nr], **kwargs)
[docs]class SimpleProteinPlotter(SimpleTracePlotter):
[docs] def protein_trace(self, protein, smooth=None, color=('c', 'm', 'y'), **kwargs): # assumes protein is reader object # TODO: iterate over chains? bb = protein.parse_selection("protein and backbone") coords = bb.get_positions() cdiff = traces.diff(coords) split = np.argwhere(cdiff > 2.5) # TODO: magic constant ns = len(split) if ns == 0: self.single_trace(smooth(coords), color=color[0], **kwargs) # TODO: color conversion is buggy else: split.shape = (ns,) for nr, csplit in enumerate([0] + split.tolist()): cc = color[nr % len(color)] if nr == ns: scoords = coords[csplit + 1:] elif nr == 0: scoords = coords[csplit:split[nr]] else: scoords = coords[csplit + 1:split[nr]] if smooth: scoords = smooth(scoords) self.single_trace(scoords, color=color, **kwargs)
[docs]class SimplePathPlotter(SimpleTracePlotter):
[docs] def single_path_traces(self, spaths, smooth=None, color=('r', 'g', 'b'), **kwargs): for spath in spaths: self.path_trace(spath.get_coords(smooth), color=color, **kwargs)
[docs]class MPLTracePlotter(SimplePathPlotter, SimpleProteinPlotter):
[docs] @showit def init_ax(self): self.fig = plt.figure() self.ax = self.fig.add_subplot(111, projection='3d') self.fig.subplots_adjust(left=0, bottom=0, right=1, top=1) self.fig.set_facecolor('w') self.ax.set_axis_bgcolor('none') self.ax.axis('off')
[docs] @showit def plot_line(self, coords, color, **kwargs): self.ax.plot3D(coords[:, 0], coords[:, 1], coords[:, 2], c=color, **kwargs)
[docs] @showit def scatter(self, coords, **kwargs): self.ax.scatter3D(coords[:, 0], coords[:, 1], coords[:, 2], **kwargs)