In this notebook implements an interactive 3-D trajectories visualizer. To visualize trajectories you need simulatte the trajectories first.
For more info see PyBroMo Homepage.
Together with a few standard python libraries we import PyBroMo using the short name pbm
.
All PyBroMo functions will be available as pbm.
something.
%matplotlib inline
import numpy as np
import tables
import matplotlib.pyplot as plt
import pybromo as pbm
print('Numpy version:', np.__version__)
print('PyTables version:', tables.__version__)
print('PyBroMo version:', pbm.__version__)
%matplotlib qt
import seaborn as sns
sns.set_style('whitegrid')
S = pbm.manage.load_trajectories('pybromo_4bce*')
from PyQt4 import QtGui, QtCore
class TrackPlotter:
def __init__(self, S, particles=None, duration=0.01, decimate=100, scale=1, page_step=100):
if particles is None:
particles = range(S.num_particles)
self.particles = particles
self.S = S
self.position = S.position
self.duration = duration
self.decimate = decimate
self.scale = scale
self.page_step = page_step
self.duration_steps = duration//S.t_step
self.num_points = self.duration_steps//decimate
self.fig, self.AX = plt.subplots(1, 2, figsize=(11, 5), sharey=True)
# Retrive the QMainWindow used by current figure and add a toolbar
# to host the new widgets
QMainWin = self.fig.canvas.parent()
toolbar = QtGui.QToolBar(QMainWin)
#QMainWin.addToolBar(QtCore.Qt.BottomToolBarArea, toolbar)
QMainWin.addToolBar(QtCore.Qt.TopToolBarArea, toolbar)
# Create the slider and spinbox for x-axis scrolling in toolbar
self.set_slider(toolbar)
self.setup_plot()
self.update()
def set_limits(self):
self.smin = 0
self.smax = self.position.shape[-1]
self.width = self.num_points*self.decimate
def set_slider(self, parent):
self.set_limits()
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, parent=parent)
self.slider.setTickPosition(QtGui.QSlider.TicksAbove)
self.slider.setTickInterval((self.smax - self.smin) / 10. * self.scale)
self.slider.setMinimum(self.smin * self.scale)
if (self.smax - self.width) > 0:
self.slider.setMaximum((self.smax - self.width) * self.scale)
else:
self.slider.setMaximum(self.smax * self.scale)
self.slider.setSingleStep(self.width * self.scale/4.)
self.slider.setPageStep(self.page_step * self.width * self.scale)
self.slider.setValue(self.smin * self.scale) # set the initial position
self.slider.valueChanged.connect(self.xpos_changed)
parent.addWidget(self.slider)
def xpos_changed(self, pos):
pos /= self.scale
slice_ = (pos, pos + self.duration_steps, self.decimate)
self.update(slice_)
def setup_plot(self):
fig, AX = self.fig, self.AX
plt.subplots_adjust(left=0.05, right=0.93, top=0.95, bottom=0.09,
wspace=0.05)
self.title_suffix = "Total: %.1f s, Visualized: %.2f ms" % (
self.S.t_step*self.S.n_samples, self.duration*1e3)
AX[1].set_xlabel("z (um)")
AX[0].set_xlabel("x (um)")
AX[0].set_ylabel("y (um)")
sig = np.array([0.2, 0.2, 0.6])*1e-6
## Draw an outline of the PSF
a = np.arange(360)/360.*2*np.pi
rx, ry, rz = (sig) # draw radius at 3 sigma
AX[0].plot((rx*np.cos(a))*1e6, (ry*np.sin(a))*1e6, lw=2, color='k')
AX[1].plot((rz*np.cos(a))*1e6, (ry*np.sin(a))*1e6, lw=2, color='k')
lines_xy, lines_zy = [], []
for ip in self.particles:
plot_kwargs = dict(ls='', marker='o', mew=0, ms=2,
alpha=0.5, label='P%d' % ip)
l_xy, = AX[0].plot([], [], **plot_kwargs)
l_zy, = AX[1].plot([], [], color=l_xy.get_color(), **plot_kwargs)
lines_xy.append(l_xy)
lines_zy.append(l_zy)
self.lines_xy = lines_xy
self.lines_zy = lines_zy
if len(self.particles) <= 20:
AX[1].legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
AX[0].set_xlim(-4, 4)
AX[0].set_ylim(-4, 4)
AX[1].set_xlim(-4, 4)
for ax in AX:
ax.autoscale(False)
fig.canvas.draw()
self.background = fig.canvas.copy_from_bbox(fig.bbox)
self.title = plt.suptitle('')
def update(self, slice_=None):
if slice_ is None:
slice_ = (0, self.duration_steps, self.decimate)
slice_ = slice(*slice_)
pos = self.position[:, :, slice_]
self.fig.canvas.restore_region(self.background)
for ip, l_xy, l_zy in zip(self.particles, self.lines_xy, self.lines_zy):
x, y, z = pos[ip, 0], pos[ip, 1], pos[ip, 2]
l_xy.set_data(x*1e6, y*1e6)
l_zy.set_data(z*1e6, y*1e6)
self.AX[0].draw_artist(l_xy)
self.AX[1].draw_artist(l_zy)
time = slice_.start * self.S.t_step
self.title.set_text("t = %5.1fs %s" % (time, self.title_suffix))
self.fig.draw_artist(self.title)
self.fig.canvas.blit(self.fig.bbox)
plt.close('all')
p = TrackPlotter(S, duration=0.02, decimate=100)
import matplotlib.gridspec as gridspec
from matplotlib import cm
from PyQt4 import QtGui, QtCore
class TrackEmPlotter:
def __init__(self, S, particles=None, duration=0.01, decimate=100, scale=1, page_step=100):
if particles is None:
particles = range(S.num_particles)
self.particles = particles
self.S = S
self.position = S.position
self.duration = duration
self.decimate = decimate
self.scale = scale
self.page_step = page_step
self.duration_steps = duration//S.t_step
self.num_points = self.duration_steps//decimate
self.create_figure()
# Retrive the QMainWindow used by current figure and add a toolbar
# to host the new widgets
QMainWin = self.fig.canvas.parent()
toolbar = QtGui.QToolBar(QMainWin)
#QMainWin.addToolBar(QtCore.Qt.BottomToolBarArea, toolbar)
QMainWin.addToolBar(QtCore.Qt.TopToolBarArea, toolbar)
# Create the slider and spinbox for x-axis scrolling in toolbar
self.set_slider(toolbar)
self.init_plot()
self.update()
def create_figure(self):
self.fig = plt.figure(figsize=(11,8))
gs = gridspec.GridSpec(2, 2, height_ratios=[2, 1])
ax1 = self.fig.add_subplot(gs[0, 0])
ax2 = self.fig.add_subplot(gs[0, 1], sharey=ax1)
plt.setp(ax2.get_yticklabels(), visible=False)
ax3 = self.fig.add_subplot(gs[1, :])
self.AX = [ax1, ax2, ax3]
def set_limits(self):
self.smin = 0
self.smax = self.position.shape[-1]
self.width = self.num_points*self.decimate
def set_slider(self, parent):
self.set_limits()
self.slider = QtGui.QSlider(QtCore.Qt.Horizontal, parent=parent)
self.slider.setTickPosition(QtGui.QSlider.TicksAbove)
self.slider.setTickInterval((self.smax - self.smin) / 10. * self.scale)
self.slider.setMinimum(self.smin * self.scale)
if (self.smax - self.width) > 0:
self.slider.setMaximum((self.smax - self.width) * self.scale)
else:
self.slider.setMaximum(self.smax * self.scale)
self.slider.setSingleStep(self.width * self.scale/4.)
self.slider.setPageStep(self.page_step * self.width * self.scale)
self.slider.setValue(self.smin * self.scale) # set the initial position
self.slider.valueChanged.connect(self.xpos_changed)
parent.addWidget(self.slider)
def xpos_changed(self, pos):
pos /= self.scale
slice_ = (pos, pos + self.duration_steps, self.decimate)
self.update(slice_)
def plot_psf(self):
psf = np.concatenate((S.psf.hdata[:, :0:-1], S.psf.hdata), axis=1)
cmap = cm.YlGnBu
cmap.set_under(alpha=0)
kwargs = dict(interpolation='nearest', cmap=cmap, vmin=1e-1, zorder=1)
self.AX[1].imshow(psf.T, extent=(-6, 6, -4, 4), **kwargs)
x = np.concatenate((-self.S.psf.xi[:0:-1], self.S.psf.xi))*1e-6
X, Y = np.meshgrid(x, x)
R = np.sqrt(X**2 + Y**2)
psf_xy = S.psf.eval_xz(R, 0)
self.AX[0].imshow(psf_xy, extent=(-4, 4, -4, 4), **kwargs)
def init_plot(self):
fig, AX = self.fig, self.AX
plt.subplots_adjust(left=0.05, right=0.93, top=0.95, bottom=0.09,
wspace=0.05)
self.title_suffix = "Total: %.1f s, Visualized: %.2f ms" % (
self.S.t_step*self.S.n_samples, self.duration*1e3)
AX[1].set_xlabel("z (um)")
AX[0].set_xlabel("x (um)")
AX[0].set_ylabel("y (um)")
AX[2].set_xlabel("Time (ms)")
self.plot_psf()
pal = sns.color_palette()
colors = pal[1:]
par_counts = [c[1] for c in self.S.particles.diffusion_coeff_counts]
em_y = np.zeros(self.num_points)
em_x = np.arange(self.num_points)*self.S.t_step*self.decimate*1e3
lines_xy, lines_zy, lines_em = [], [], []
for ip in self.particles:
color = colors[0] if ip < par_counts[0] else colors[1]
plot_kwargs = dict(ls='', marker='o', mew=0, ms=2, color=color,
alpha=0.5, label='P%d' % ip)
l_xy, = AX[0].plot([], [], **plot_kwargs)
l_zy, = AX[1].plot([], [], **plot_kwargs)
em_kw = dict(alpha=0.8, ls='-', color=color)
l_em, = AX[2].plot(em_x, em_y, **em_kw)
lines_xy.append(l_xy)
lines_zy.append(l_zy)
lines_em.append(l_em)
self.lines_xy = lines_xy
self.lines_zy = lines_zy
self.lines_em = lines_em
if len(self.particles) <= 20:
AX[1].legend(bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0.)
AX[0].set_xlim(-4, 4)
AX[0].set_ylim(-4, 4)
AX[1].set_xlim(-4, 4)
AX[2].set_ylim(0, 1)
for ax in AX:
ax.autoscale(False)
ax.set_axisbelow(True)
fig.canvas.draw()
self.background = fig.canvas.copy_from_bbox(fig.bbox)
self.title = plt.suptitle('')
def update(self, slice_=None):
if slice_ is None:
slice_ = (0, self.duration_steps, self.decimate)
slice_ = slice(*slice_)
assert (slice_.stop - slice_.start)//self.decimate == self.num_points
pos = self.position[:, :, slice_]
emission = self.S.emission[:, slice_]
self.fig.canvas.restore_region(self.background)
for ip, l_xy, l_zy, l_em in zip(self.particles,
self.lines_xy, self.lines_zy,
self.lines_em):
x, y, z = pos[ip, 0], pos[ip, 1], pos[ip, 2]
l_xy.set_data(x*1e6, y*1e6)
l_zy.set_data(z*1e6, y*1e6)
l_em.set_ydata(emission[ip])
self.AX[0].draw_artist(l_xy)
self.AX[1].draw_artist(l_zy)
self.AX[2].draw_artist(l_em)
time = slice_.start * self.S.t_step
self.title.set_text("t = %5.1fs %s" % (time, self.title_suffix))
self.fig.draw_artist(self.title)
self.fig.canvas.blit(self.fig.bbox)
plt.close('all')
p = TrackEmPlotter(S)