# -*- coding: utf-8 -*-
#
# University of Illinois Open Source License
# Copyright 2008-2018 Luthey-Schulten Group,
# All rights reserved.
#
# Developed by: Luthey-Schulten Group
# University of Illinois at Urbana-Champaign
# http://www.scs.uiuc.edu/~schulten
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the Software), to deal with
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to
# do so, subject to the following conditions:
#
# - Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimers.
#
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimers in the documentation
# and/or other materials provided with the distribution.
#
# - Neither the names of the Luthey-Schulten Group, University of Illinois at
# Urbana-Champaign, nor the names of its contributors may be used to endorse or
# promote products derived from this Software without specific prior written
# permission.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS WITH THE SOFTWARE.
#
# Author(s): Joseph R. Peterson
#
#
import lm
import pyLM
[docs]
def getReactionString(rct, prd, rate):
rxnStr = ""
if isinstance(rct,str):
if rct == '':
rct = '∅'
rct = [rct]
if isinstance(prd,str):
if prd == '':
prd = '∅'
prd = [prd]
rxnStr += " + ".join(rct)
rxnStr += " ⟶ "
rxnStr += " + ".join(prd)
units = "?"
if len(rct) == 0:
units = "molecules/s"
elif len(rct) == 1:
units = "s⁻¹"
elif len(rct) == 2:
units = "molecule⁻¹sec⁻¹"
return rxnStr, rate, units
[docs]
def writeTable(columnNames,rows):
# Table definitions
cols = len(columnNames)
headerStyle = '<td style="text-align:%s"><b>%s</b></td>'
rowStyle = '<td style="text-align:%s">%s</td>'
def align(idx):
if idx == 0:
return "left"
return "center"
s = ''
# Write header
s += '<table>'
s += '<tr>%s</tr>'%("".join([headerStyle%(align(i), x) for i,x in enumerate(columnNames)]))
for row in rows:
s += '<tr>%s</tr>'%("".join([rowStyle%(align(i), x) for i,x in enumerate(row)]))
# Write footer
s += '</table>'
return s
[docs]
def visualizeRDMEInitialConditions(sim):
'''Visualize the RDME simulation volume inside Jupyter.
Use the '%matplotlib notebook' magic to enable
interactive picking of points.
Args:
sim (RDMESimulation): The simulation to visualize.
'''
# Error checking
if not isinstance(sim, pyLM.RDME.RDMESimulation):
raise TypeError("Can only visualize RDME simulations.")
# Start widgets
import ipywidgets as widgets
from IPython import display
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
if matplotlib.get_backend() != 'nbAgg':
raise RuntimeError("This widget requires the nbAgg backend. Restart the notebook with `%matplotlib notebook'")
plt.ion()
# Get a discretized version of the lattice and dimensions
lattice = None
try:
lattice = sim.lattice
except:
lattice = sim.getLattice()
siteLattice = lattice.getSiteLatticeView()
particleLattice = lattice.getParticleLatticeView()
nx, ny, nz = lattice.getXSize()-1, lattice.getYSize()-1, lattice.getZSize()-1
ns = {"X":nx, "Y":ny, "Z":nz}
# Selector and slider
# Top Section
label1 = widgets.HTML(value="<h2>Site Data</h2>")
toggle = widgets.ToggleButtons(options=["X","Y","Z"], description="Slice:", disabled=False)
slider = widgets.IntSlider(value=0, min=0, max=nx, description="X:", orientation='horizontal', readout=False)
intField = widgets.IntText(value = 0)
# Bottom Section
label2 = widgets.HTML(value="<h2>Particle Data</h2>")
particleSelector = widgets.SelectMultiple(options=sim.species_id, description="Particles")
# Info Section
label3 = widgets.HTML(value="<h2>Info</h2>")
position = widgets.HTML(value="Position: N/A")
siteType = widgets.HTML(value="Site Type: N/A")
particles = widgets.HTML(value="Particles: N/A")
# Advanced Settings
siteCmapSelector = widgets.Dropdown(options = sorted(m for m in plt.cm.datad if not m.endswith("_r")),
value = 'Accent',
description = 'Site Type Colormap:')
particleCmapSelector = widgets.Dropdown(options = sorted(m for m in plt.cm.datad if not m.endswith("_r")),
value = 'Set2',
description = 'Particle Colormap:')
radiusPicker = widgets.IntText(value=0, description='Picker Radius (pixels):')
settingsBox = widgets.VBox([radiusPicker,siteCmapSelector,particleCmapSelector])
settings = widgets.Accordion(children=[settingsBox],selected_index=None)
settings.set_title(0, 'Advanced Options')
# Create plot and plot change function
plt.figure(figsize=(12,5))
ax = plt.gca()
fig = plt.gcf()
# Show site lattice
sdata = siteLattice[:,:,slider.value].transpose()
image = ax.imshow(sdata,
interpolation='none',
vmin=0, vmax=len(sim.siteTypes.items()),
cmap=plt.get_cmap(siteCmapSelector.value, len(sim.siteTypes.items()))) # Z, Y, X
ax.set_xlabel("Z (nm)")
ax.set_ylabel("Y (nm)")
ax.set_xticklabels([i * sim.latticeSpacing/1e-9 for i in ax.get_xticks()])
ax.set_yticklabels([i * sim.latticeSpacing/1e-9 for i in ax.get_yticks()])
cbar = fig.colorbar(image, ticks=np.arange(len(sim.siteTypes))+0.5)
cbar.ax.set_yticklabels([x[0] for x in sorted(sim.siteTypes.items(), key=lambda x:x[1])])
# Show particle lattice
pdata = np.zeros(shape=sdata.shape)
if len(particleSelector.value) > 0:
for p in particleSelector.value:
pidx = sim.species_id.index(p)+1
for i, j in np.argwhere(particleLattice[0,:,:,slider.value] == pidx)[:,0:2]:
pdata[j,i] = pidx
image2 = ax.imshow(np.ma.masked_where(pdata==0, pdata),
interpolation='none',
vmin=0, vmax=len(sim.species_id)+1,
cmap=plt.get_cmap(particleCmapSelector.value, len(sim.species_id)+1))
cbar2 = fig.colorbar(image2, ticks=np.arange(len(sim.species_id)+1)+0.5)
cbar2.ax.set_yticklabels([''] + sim.species_id)
# Update the plot
def updatePlot():
sdata = None
if toggle.value == "X":
sdata = siteLattice[:,::-1,slider.value].transpose()
ax.set_xlabel("Z (nm)")
ax.set_ylabel("Y (nm)")
image.set_extent([0,nz,0,ny])
image2.set_extent([0,nz,0,ny])
elif toggle.value == "Y":
sdata = siteLattice[:,slider.value,::-1].transpose()
ax.set_xlabel("Z (nm)")
ax.set_ylabel("X (nm)")
image.set_extent([0,nz,0,nx])
image2.set_extent([0,nz,0,nx])
elif toggle.value == "Z":
sdata = siteLattice[slider.value,::-1,:].transpose()
ax.set_xlabel("X (nm)")
ax.set_ylabel("Y (nm)")
image.set_extent([0,nx,0,ny])
image2.set_extent([0,nx,0,ny])
# Extract particle data
pdata = np.zeros(shape=sdata.shape)
if len(particleSelector.value) > 0:
for p in particleSelector.value:
pidx = sim.species_id.index(p)+1
if toggle.value == "X":
for i, j in np.argwhere(particleLattice[:,:,:,slider.value] == pidx)[:,1:3]:
pdata[ny-j,i] = pidx
elif toggle.value == "Y":
for i, j in np.argwhere(particleLattice[:,:,slider.value,:] == pidx)[:,1:3]:
pdata[nx-j,i] = pidx
elif toggle.value == "Z":
for i, j in np.argwhere(particleLattice[:,slider.value,:,:] == pidx)[:,1:3]:
pdata[j,nx-i] = pidx
ax.set_xticklabels([i * sim.latticeSpacing/1e-9 for i in ax.get_xticks()])
ax.set_yticklabels([i * sim.latticeSpacing/1e-9 for i in ax.get_yticks()])
image.set_data(sdata)
image2.set_data(np.ma.masked_where(pdata==0, pdata))
# Define GUI callback functions
def onDimChange(change):
slider.description = change["new"] + ":"
slider.max = ns[change["new"]]
slider.value = 0
# Update the matplotlib image
updatePlot()
def onSliderChange(change):
# Update value in the int field
intField.value = change["new"]
# Update the matplotlib image
updatePlot()
def onParticleSelector(change):
# Update the matplotlib image
updatePlot()
def onTextChange(change):
# Update value in the int field
newVal = change["new"]
if newVal < slider.min:
newVal = slider.min
if newVal > slider.max:
newVal = slider.max
slider.value = newVal
intField.value = newVal
# Update the matplotlib image
updatePlot()
def changeColormap(change):
# Update colormaps
image.set_cmap(plt.get_cmap(siteCmapSelector.value, len(sim.siteTypes.items())))
image2.set_cmap(plt.get_cmap(particleCmapSelector.value, len(sim.species_id)+1))
cbar.ax.set_yticklabels([x[0] for x in sorted(sim.siteTypes.items(), key=lambda x:x[1])])
cbar2.ax.set_yticklabels([''] + sim.species_id)
# Update the matplot images
updatePlot()
# Register GUI interactions
toggle.observe(onDimChange, names="value")
slider.observe(onSliderChange, names="value")
particleSelector.observe(onParticleSelector, names="value")
intField.observe(onTextChange, names="value")
siteCmapSelector.observe(changeColormap, names="value")
particleCmapSelector.observe(changeColormap, names="value")
# Create GUI elements
topBox = widgets.VBox([label1,toggle,widgets.HBox([slider,intField])])
particleBox = widgets.VBox([label2,particleSelector])
infoBox = widgets.VBox([label3, position, siteType, particles])
bottomBox = widgets.HBox([particleBox, infoBox])
totalBox = widgets.VBox([topBox,bottomBox,settings])
# Interaction with matplotlib interactive
def onRelease(event):
# Update the position that was clicked
position.value = "Position: %0.1fnm, %0.1fnm (%d, %d)"%(event.xdata*sim.latticeSpacing/1e-9, event.ydata*sim.latticeSpacing/1e-9, event.xdata, event.ydata)
X, Y = int(event.xdata), int(event.ydata)
r = radiusPicker.value
# Update the info for the site type that was clicked
localsd = None
thest = None
if toggle.value == "X":
localsd = siteLattice[:,:,slider.value].transpose()
thest = [x[0] for x in sorted(sim.siteTypes.items(), key=lambda x:x[1])][localsd[Y,X]]
elif toggle.value == "Y":
localsd = siteLattice[:,slider.value,:].transpose()
thest = [x[0] for x in sorted(sim.siteTypes.items(), key=lambda x:x[1])][localsd[Y,X]]
elif toggle.value == "Z":
localsd = siteLattice[slider.value,:,:].transpose()
thest = [x[0] for x in sorted(sim.siteTypes.items(), key=lambda x:x[1])][localsd[X,Y]]
siteType.value="Site Type: %s"%(thest)
# Update the particles at the clicked location
pmap = {}
for partName, partID in sim.particleMap.items():
particleLattice = sim.lattice.getParticleLatticeView()
if toggle.value == "X":
val = np.sum(particleLattice[:,max(0,X-r):min(X+r,nz),max(0,Y-r):min(Y+r,ny),slider.value,:] == partID)
if val > 0:
pmap[partName] = val
elif toggle.value == "Y":
val = np.sum(particleLattice[:,max(0,X-r):min(X+r,nz),slider.value,max(0,Y-r):min(Y+r,nx),:] == partID)
if val > 0:
pmap[partName] = val
elif toggle.value == "Z":
val = np.sum(particleLattice[:,slider.value,max(0,Y-r):min(Y+r,ny),max(0,X-r):min(X+r,nx),:] == partID)
if val > 0:
pmap[partName] = val
if len(pmap) == 0:
particles.value = "Particles: N/A"
else:
particles.value = "Particles: %s"%(",".join(["%dx%s"%(count, part) for part, count in pmap.items()]))
# Register interactive commands
cid_up = fig.canvas.mpl_connect('button_release_event', onRelease)
# Execute widget
display.display(totalBox)